[gobject-introspection/wip/cmph-rebase3: 2/9] Import CMPH 1.0



commit a94b6f863e7385871d78d79cd90522f51cdc6283
Author: Colin Walters <walters verbum org>
Date:   Thu Nov 11 15:01:07 2010 -0500

    Import CMPH 1.0
    
    This will be used for typelib indexing.  See README-CMPH-IMPORT.txt
    for more information.

 girepository/cmph/README-CMPH-IMPORT.txt |    5 +
 girepository/cmph/bdz.c                  |  703 +++++++++++++++++++++
 girepository/cmph/bdz.h                  |   43 ++
 girepository/cmph/bdz_gen_lookup_table.c |   33 +
 girepository/cmph/bdz_ph.c               |  621 +++++++++++++++++++
 girepository/cmph/bdz_ph.h               |   42 ++
 girepository/cmph/bdz_structs.h          |   36 ++
 girepository/cmph/bdz_structs_ph.h       |   26 +
 girepository/cmph/bitbool.h              |  179 ++++++
 girepository/cmph/bmz.c                  |  620 +++++++++++++++++++
 girepository/cmph/bmz.h                  |   42 ++
 girepository/cmph/bmz8.c                 |  632 +++++++++++++++++++
 girepository/cmph/bmz8.h                 |   42 ++
 girepository/cmph/bmz8_structs.h         |   25 +
 girepository/cmph/bmz_structs.h          |   25 +
 girepository/cmph/brz.c                  |  985 +++++++++++++++++++++++++++++
 girepository/cmph/brz.h                  |   47 ++
 girepository/cmph/brz_structs.h          |   39 ++
 girepository/cmph/buffer_entry.c         |  103 +++
 girepository/cmph/buffer_entry.h         |   14 +
 girepository/cmph/buffer_manage.c        |   66 ++
 girepository/cmph/buffer_manage.h        |   12 +
 girepository/cmph/buffer_manager.c       |   64 ++
 girepository/cmph/buffer_manager.h       |   12 +
 girepository/cmph/chd.c                  |  271 ++++++++
 girepository/cmph/chd.h                  |   59 ++
 girepository/cmph/chd_ph.c               |  988 ++++++++++++++++++++++++++++++
 girepository/cmph/chd_ph.h               |   59 ++
 girepository/cmph/chd_structs.h          |   21 +
 girepository/cmph/chd_structs_ph.h       |   29 +
 girepository/cmph/chm.c                  |  381 ++++++++++++
 girepository/cmph/chm.h                  |   42 ++
 girepository/cmph/chm_structs.h          |   24 +
 girepository/cmph/cmph.c                 |  845 +++++++++++++++++++++++++
 girepository/cmph/cmph.h                 |  112 ++++
 girepository/cmph/cmph_structs.c         |   69 ++
 girepository/cmph/cmph_structs.h         |   33 +
 girepository/cmph/cmph_time.h            |   62 ++
 girepository/cmph/cmph_types.h           |   42 ++
 girepository/cmph/compressed_rank.c      |  321 ++++++++++
 girepository/cmph/compressed_rank.h      |   55 ++
 girepository/cmph/compressed_seq.c       |  378 ++++++++++++
 girepository/cmph/compressed_seq.h       |   84 +++
 girepository/cmph/debug.h                |   53 ++
 girepository/cmph/djb2_hash.c            |   49 ++
 girepository/cmph/djb2_hash.h            |   18 +
 girepository/cmph/fch.c                  |  517 ++++++++++++++++
 girepository/cmph/fch.h                  |   48 ++
 girepository/cmph/fch_buckets.c          |  214 +++++++
 girepository/cmph/fch_buckets.h          |   30 +
 girepository/cmph/fch_structs.h          |   30 +
 girepository/cmph/fnv_hash.c             |   53 ++
 girepository/cmph/fnv_hash.h             |   18 +
 girepository/cmph/graph.c                |  338 ++++++++++
 girepository/cmph/graph.h                |   40 ++
 girepository/cmph/hash.c                 |  216 +++++++
 girepository/cmph/hash.h                 |   76 +++
 girepository/cmph/hash_state.h           |   12 +
 girepository/cmph/hashtree.c             |  289 +++++++++
 girepository/cmph/hashtree.h             |   19 +
 girepository/cmph/hashtree_structs.h     |   32 +
 girepository/cmph/jenkins_hash.c         |  297 +++++++++
 girepository/cmph/jenkins_hash.h         |   65 ++
 girepository/cmph/main.c                 |  342 +++++++++++
 girepository/cmph/miller_rabin.c         |   67 ++
 girepository/cmph/miller_rabin.h         |    5 +
 girepository/cmph/sdbm_hash.c            |   49 ++
 girepository/cmph/sdbm_hash.h            |   18 +
 girepository/cmph/select.c               |  337 ++++++++++
 girepository/cmph/select.h               |   61 ++
 girepository/cmph/select_lookup_tables.h |  170 +++++
 girepository/cmph/vqueue.c               |   51 ++
 girepository/cmph/vqueue.h               |   18 +
 girepository/cmph/vstack.c               |   79 +++
 girepository/cmph/vstack.h               |   18 +
 girepository/cmph/wingetopt.c            |  179 ++++++
 girepository/cmph/wingetopt.h            |   25 +
 77 files changed, 12124 insertions(+), 0 deletions(-)
---
diff --git a/girepository/cmph/README-CMPH-IMPORT.txt b/girepository/cmph/README-CMPH-IMPORT.txt
new file mode 100644
index 0000000..a1c23c2
--- /dev/null
+++ b/girepository/cmph/README-CMPH-IMPORT.txt
@@ -0,0 +1,5 @@
+This import of CMPH was made from revision bfdcc3a3a18dfb9 of
+git://cmph.git.sourceforge.net/gitroot/cmph/cmph
+
+Only the following files were taken, and everything else deleted:
+COPYING src/*.[ch]
diff --git a/girepository/cmph/bdz.c b/girepository/cmph/bdz.c
new file mode 100755
index 0000000..f422c8f
--- /dev/null
+++ b/girepository/cmph/bdz.c
@@ -0,0 +1,703 @@
+#include "bdz.h"
+#include "cmph_structs.h"
+#include "bdz_structs.h"
+#include "hash.h"
+#include "bitbool.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+//#define DEBUG
+#include "debug.h"
+#define UNASSIGNED 3U
+#define NULL_EDGE 0xffffffff
+
+//cmph_uint32 ngrafos = 0;
+//cmph_uint32 ngrafos_aciclicos = 0;
+// table used for looking up the number of assigned vertices  a 8-bit integer
+const cmph_uint8 bdz_lookup_table[] =
+{
+4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 3, 3, 3, 3, 2,
+4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 3, 3, 3, 3, 2,
+4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 3, 3, 3, 3, 2,
+3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 2, 2, 2, 2, 1,
+4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 3, 3, 3, 3, 2,
+4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 3, 3, 3, 3, 2,
+4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 3, 3, 3, 3, 2,
+3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 2, 2, 2, 2, 1,
+4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 3, 3, 3, 3, 2,
+4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 3, 3, 3, 3, 2,
+4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 3, 3, 3, 3, 2,
+3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 2, 2, 2, 2, 1,
+3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 2, 2, 2, 2, 1,
+3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 2, 2, 2, 2, 1,
+3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 2, 2, 2, 2, 1,
+2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 1, 1, 1, 1, 0
+};	
+
+typedef struct 
+{
+	cmph_uint32 vertices[3];
+	cmph_uint32 next_edges[3];
+}bdz_edge_t;
+
+typedef cmph_uint32 * bdz_queue_t;
+
+static void bdz_alloc_queue(bdz_queue_t * queuep, cmph_uint32 nedges)
+{
+	(*queuep)=malloc(nedges*sizeof(cmph_uint32));
+};
+static void bdz_free_queue(bdz_queue_t * queue)
+{
+	free(*queue);
+};
+
+typedef struct 
+{
+	cmph_uint32 nedges;
+	bdz_edge_t * edges;
+	cmph_uint32 * first_edge;
+	cmph_uint8 * vert_degree;	
+}bdz_graph3_t;
+
+
+static void bdz_alloc_graph3(bdz_graph3_t * graph3, cmph_uint32 nedges, cmph_uint32 nvertices)
+{
+	graph3->edges=malloc(nedges*sizeof(bdz_edge_t));
+	graph3->first_edge=malloc(nvertices*sizeof(cmph_uint32));
+	graph3->vert_degree=malloc((size_t)nvertices);	
+};
+static void bdz_init_graph3(bdz_graph3_t * graph3, cmph_uint32 nedges, cmph_uint32 nvertices)
+{
+	memset(graph3->first_edge,0xff,nvertices*sizeof(cmph_uint32));
+	memset(graph3->vert_degree,0,(size_t)nvertices);
+	graph3->nedges=0;
+};
+static void bdz_free_graph3(bdz_graph3_t *graph3)
+{
+	free(graph3->edges);
+	free(graph3->first_edge);
+	free(graph3->vert_degree);
+};
+
+static void bdz_partial_free_graph3(bdz_graph3_t *graph3)
+{
+	free(graph3->first_edge);
+	free(graph3->vert_degree);
+	graph3->first_edge = NULL;
+	graph3->vert_degree = NULL;
+};
+
+static void bdz_add_edge(bdz_graph3_t * graph3, cmph_uint32 v0, cmph_uint32 v1, cmph_uint32 v2)
+{
+	graph3->edges[graph3->nedges].vertices[0]=v0;
+	graph3->edges[graph3->nedges].vertices[1]=v1;
+	graph3->edges[graph3->nedges].vertices[2]=v2;
+	graph3->edges[graph3->nedges].next_edges[0]=graph3->first_edge[v0];
+	graph3->edges[graph3->nedges].next_edges[1]=graph3->first_edge[v1];
+	graph3->edges[graph3->nedges].next_edges[2]=graph3->first_edge[v2];
+	graph3->first_edge[v0]=graph3->first_edge[v1]=graph3->first_edge[v2]=graph3->nedges;
+	graph3->vert_degree[v0]++;
+	graph3->vert_degree[v1]++;
+	graph3->vert_degree[v2]++;
+	graph3->nedges++;
+};
+
+static void bdz_dump_graph(bdz_graph3_t* graph3, cmph_uint32 nedges, cmph_uint32 nvertices)
+{
+	int i;
+	for(i=0;i<nedges;i++){
+		printf("\nedge %d %d %d %d ",i,graph3->edges[i].vertices[0],
+			graph3->edges[i].vertices[1],graph3->edges[i].vertices[2]);
+		printf(" nexts %d %d %d",graph3->edges[i].next_edges[0],
+				graph3->edges[i].next_edges[1],graph3->edges[i].next_edges[2]);
+	};
+	
+	for(i=0;i<nvertices;i++){
+		printf("\nfirst for vertice %d %d ",i,graph3->first_edge[i]);
+	
+	};
+};
+
+static void bdz_remove_edge(bdz_graph3_t * graph3, cmph_uint32 curr_edge)
+{
+	cmph_uint32 i,j=0,vert,edge1,edge2;
+	for(i=0;i<3;i++){
+		vert=graph3->edges[curr_edge].vertices[i];
+		edge1=graph3->first_edge[vert];
+		edge2=NULL_EDGE;
+		while(edge1!=curr_edge&&edge1!=NULL_EDGE){
+			edge2=edge1;
+			if(graph3->edges[edge1].vertices[0]==vert){
+				j=0;
+			} else if(graph3->edges[edge1].vertices[1]==vert){
+				j=1;
+			} else 
+				j=2;
+			edge1=graph3->edges[edge1].next_edges[j];
+		};
+		if(edge1==NULL_EDGE){
+			printf("\nerror remove edge %d dump graph",curr_edge);
+			bdz_dump_graph(graph3,graph3->nedges,graph3->nedges+graph3->nedges/4);
+			exit(-1);
+		};
+		
+		if(edge2!=NULL_EDGE){
+			graph3->edges[edge2].next_edges[j] = 
+				graph3->edges[edge1].next_edges[i];
+		} else 
+			graph3->first_edge[vert]=
+				graph3->edges[edge1].next_edges[i];
+		graph3->vert_degree[vert]--;
+	};
+	
+};
+
+static int bdz_generate_queue(cmph_uint32 nedges, cmph_uint32 nvertices, bdz_queue_t queue, bdz_graph3_t* graph3)
+{
+	cmph_uint32 i,v0,v1,v2;
+	cmph_uint32 queue_head=0,queue_tail=0;
+	cmph_uint32 curr_edge;
+	cmph_uint32 tmp_edge;
+	cmph_uint8 * marked_edge =malloc((size_t)(nedges >> 3) + 1);
+	memset(marked_edge, 0, (size_t)(nedges >> 3) + 1);
+
+	for(i=0;i<nedges;i++){
+		v0=graph3->edges[i].vertices[0];
+		v1=graph3->edges[i].vertices[1];
+		v2=graph3->edges[i].vertices[2];
+		if(graph3->vert_degree[v0]==1 || 
+				graph3->vert_degree[v1]==1 ||
+				graph3->vert_degree[v2]==1){
+			if(!GETBIT(marked_edge,i)) {
+				queue[queue_head++]=i;
+				SETBIT(marked_edge,i);
+			}
+		};
+	};
+	while(queue_tail!=queue_head){
+		curr_edge=queue[queue_tail++];
+		bdz_remove_edge(graph3,curr_edge);
+		v0=graph3->edges[curr_edge].vertices[0];
+		v1=graph3->edges[curr_edge].vertices[1];
+		v2=graph3->edges[curr_edge].vertices[2];
+		if(graph3->vert_degree[v0]==1 ) {
+			tmp_edge=graph3->first_edge[v0];
+			if(!GETBIT(marked_edge,tmp_edge)) {
+				queue[queue_head++]=tmp_edge;
+				SETBIT(marked_edge,tmp_edge);
+			};
+			
+		};
+		if(graph3->vert_degree[v1]==1) {
+			tmp_edge=graph3->first_edge[v1];
+			if(!GETBIT(marked_edge,tmp_edge)){
+				queue[queue_head++]=tmp_edge;
+				SETBIT(marked_edge,tmp_edge);
+			};
+			
+		};
+		if(graph3->vert_degree[v2]==1){
+			tmp_edge=graph3->first_edge[v2];
+			if(!GETBIT(marked_edge,tmp_edge)){
+				queue[queue_head++]=tmp_edge;
+				SETBIT(marked_edge,tmp_edge);
+			};
+		};
+	};
+	free(marked_edge);
+	return (int)(queue_head-nedges);/* returns 0 if successful otherwies return negative number*/
+};
+
+static int bdz_mapping(cmph_config_t *mph, bdz_graph3_t* graph3, bdz_queue_t queue);
+static void assigning(bdz_config_data_t *bdz, bdz_graph3_t* graph3, bdz_queue_t queue);
+static void ranking(bdz_config_data_t *bdz);
+static cmph_uint32 rank(cmph_uint32 b, cmph_uint32 * ranktable, cmph_uint8 * g, cmph_uint32 vertex);
+
+bdz_config_data_t *bdz_config_new()
+{
+	bdz_config_data_t *bdz;
+	bdz = (bdz_config_data_t *)malloc(sizeof(bdz_config_data_t));
+	assert(bdz);
+	memset(bdz, 0, sizeof(bdz_config_data_t));
+	bdz->hashfunc = CMPH_HASH_JENKINS;
+	bdz->g = NULL;
+	bdz->hl = NULL;
+	bdz->k = 0; //kth index in ranktable, $k = log_2(n=3r)/\varepsilon$
+	bdz->b = 7; // number of bits of k
+	bdz->ranktablesize = 0; //number of entries in ranktable, $n/k +1$
+	bdz->ranktable = NULL; // rank table
+	return bdz;
+}
+
+void bdz_config_destroy(cmph_config_t *mph)
+{
+	bdz_config_data_t *data = (bdz_config_data_t *)mph->data;
+	DEBUGP("Destroying algorithm dependent data\n");
+	free(data);
+}
+
+void bdz_config_set_b(cmph_config_t *mph, cmph_uint32 b)
+{
+	bdz_config_data_t *bdz = (bdz_config_data_t *)mph->data;
+	if (b <= 2 || b > 10) b = 7; // validating restrictions over parameter b.
+	bdz->b = (cmph_uint8)b;
+	DEBUGP("b: %u\n", b);
+
+}
+
+void bdz_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs)
+{
+	bdz_config_data_t *bdz = (bdz_config_data_t *)mph->data;
+	CMPH_HASH *hashptr = hashfuncs;
+	cmph_uint32 i = 0;
+	while(*hashptr != CMPH_HASH_COUNT)
+	{
+		if (i >= 1) break; //bdz only uses one linear hash function
+		bdz->hashfunc = *hashptr;	
+		++i, ++hashptr;
+	}
+}
+
+cmph_t *bdz_new(cmph_config_t *mph, double c)
+{
+	cmph_t *mphf = NULL;
+	bdz_data_t *bdzf = NULL;
+	cmph_uint32 iterations;
+	bdz_queue_t edges;
+	bdz_graph3_t graph3;
+	bdz_config_data_t *bdz = (bdz_config_data_t *)mph->data;
+	#ifdef CMPH_TIMING
+	double construction_time_begin = 0.0;
+	double construction_time = 0.0;
+	ELAPSED_TIME_IN_SECONDS(&construction_time_begin);
+	#endif
+
+
+	if (c == 0) c = 1.23; // validating restrictions over parameter c.
+	DEBUGP("c: %f\n", c);
+	bdz->m = mph->key_source->nkeys;	
+	bdz->r = (cmph_uint32)ceil((c * mph->key_source->nkeys)/3);
+	if ((bdz->r % 2) == 0) bdz->r+=1;
+	bdz->n = 3*bdz->r;
+
+	bdz->k = (1U << bdz->b);
+	DEBUGP("b: %u -- k: %u\n", bdz->b, bdz->k);
+	
+	bdz->ranktablesize = (cmph_uint32)ceil(bdz->n/(double)bdz->k);
+	DEBUGP("ranktablesize: %u\n", bdz->ranktablesize);
+
+	
+	bdz_alloc_graph3(&graph3, bdz->m, bdz->n);
+	bdz_alloc_queue(&edges,bdz->m);
+	DEBUGP("Created hypergraph\n");
+	
+	DEBUGP("m (edges): %u n (vertices): %u  r: %u c: %f \n", bdz->m, bdz->n, bdz->r, c);
+
+	// Mapping step
+	iterations = 1000;
+	if (mph->verbosity)
+	{
+		fprintf(stderr, "Entering mapping step for mph creation of %u keys with graph sized %u\n", bdz->m, bdz->n);
+	}
+	while(1)
+	{
+		int ok;
+		DEBUGP("linear hash function \n");
+		bdz->hl = hash_state_new(bdz->hashfunc, 15);
+
+		ok = bdz_mapping(mph, &graph3, edges);
+                //ok = 0;
+		if (!ok)
+		{
+			--iterations;
+			hash_state_destroy(bdz->hl);
+			bdz->hl = NULL;
+			DEBUGP("%u iterations remaining\n", iterations);
+			if (mph->verbosity)
+			{
+				fprintf(stderr, "acyclic graph creation failure - %u iterations remaining\n", iterations);
+			}
+			if (iterations == 0) break;
+		} 
+		else break;
+	}
+	
+	if (iterations == 0)
+	{
+		bdz_free_queue(&edges);
+		bdz_free_graph3(&graph3);
+		return NULL;
+	}
+	bdz_partial_free_graph3(&graph3);
+	// Assigning step
+	if (mph->verbosity)
+	{
+		fprintf(stderr, "Entering assigning step for mph creation of %u keys with graph sized %u\n", bdz->m, bdz->n);
+	}
+	assigning(bdz, &graph3, edges);
+
+	bdz_free_queue(&edges);
+	bdz_free_graph3(&graph3);
+	if (mph->verbosity)
+	{
+		fprintf(stderr, "Entering ranking step for mph creation of %u keys with graph sized %u\n", bdz->m, bdz->n);
+	}
+	ranking(bdz);
+	#ifdef CMPH_TIMING	
+	ELAPSED_TIME_IN_SECONDS(&construction_time);
+	#endif
+	mphf = (cmph_t *)malloc(sizeof(cmph_t));
+	mphf->algo = mph->algo;
+	bdzf = (bdz_data_t *)malloc(sizeof(bdz_data_t));
+	bdzf->g = bdz->g;
+	bdz->g = NULL; //transfer memory ownership
+	bdzf->hl = bdz->hl;
+	bdz->hl = NULL; //transfer memory ownership
+	bdzf->ranktable = bdz->ranktable;
+	bdz->ranktable = NULL; //transfer memory ownership
+	bdzf->ranktablesize = bdz->ranktablesize;
+	bdzf->k = bdz->k;
+	bdzf->b = bdz->b;
+	bdzf->n = bdz->n;
+	bdzf->m = bdz->m;
+	bdzf->r = bdz->r;
+	mphf->data = bdzf;
+	mphf->size = bdz->m;
+
+	DEBUGP("Successfully generated minimal perfect hash\n");
+	if (mph->verbosity)
+	{
+		fprintf(stderr, "Successfully generated minimal perfect hash function\n");
+	}
+
+
+	#ifdef CMPH_TIMING	
+	register cmph_uint32 space_usage = bdz_packed_size(mphf)*8;
+	register cmph_uint32 keys_per_bucket = 1;
+	construction_time = construction_time - construction_time_begin;
+	fprintf(stdout, "%u\t%.2f\t%u\t%.4f\t%.4f\n", bdz->m, bdz->m/(double)bdz->n, keys_per_bucket, construction_time, space_usage/(double)bdz->m);
+	#endif	
+
+	return mphf;
+}
+
+		
+static int bdz_mapping(cmph_config_t *mph, bdz_graph3_t* graph3, bdz_queue_t queue)
+{
+	cmph_uint32 e;
+	int cycles = 0;
+	cmph_uint32 hl[3];
+	bdz_config_data_t *bdz = (bdz_config_data_t *)mph->data;
+	bdz_init_graph3(graph3, bdz->m, bdz->n);
+	mph->key_source->rewind(mph->key_source->data);
+	for (e = 0; e < mph->key_source->nkeys; ++e)
+	{
+		cmph_uint32 h0, h1, h2;
+		cmph_uint32 keylen;
+		char *key = NULL;
+		mph->key_source->read(mph->key_source->data, &key, &keylen);		
+		hash_vector(bdz->hl, key, keylen,hl);
+		h0 = hl[0] % bdz->r;
+		h1 = hl[1] % bdz->r + bdz->r;
+		h2 = hl[2] % bdz->r + (bdz->r << 1);
+		mph->key_source->dispose(mph->key_source->data, key, keylen);
+		bdz_add_edge(graph3,h0,h1,h2);
+	}
+	cycles = bdz_generate_queue(bdz->m, bdz->n, queue, graph3);	
+	return (cycles == 0);
+}
+
+static void assigning(bdz_config_data_t *bdz, bdz_graph3_t* graph3, bdz_queue_t queue)
+{
+	cmph_uint32 i;
+	cmph_uint32 nedges=graph3->nedges;
+	cmph_uint32 curr_edge;
+	cmph_uint32 v0,v1,v2;
+	cmph_uint8 * marked_vertices =malloc((size_t)(bdz->n >> 3) + 1);
+        cmph_uint32 sizeg = (cmph_uint32)ceil(bdz->n/4.0);
+	bdz->g = (cmph_uint8 *)calloc((size_t)(sizeg), sizeof(cmph_uint8));	
+	memset(marked_vertices, 0, (size_t)(bdz->n >> 3) + 1);
+	memset(bdz->g, 0xff, (size_t)(sizeg));
+
+	for(i=nedges-1;i+1>=1;i--){
+		curr_edge=queue[i];
+		v0=graph3->edges[curr_edge].vertices[0];
+		v1=graph3->edges[curr_edge].vertices[1];
+		v2=graph3->edges[curr_edge].vertices[2];
+		DEBUGP("B:%u %u %u -- %u %u %u\n", v0, v1, v2, GETVALUE(bdz->g, v0), GETVALUE(bdz->g, v1), GETVALUE(bdz->g, v2));
+		if(!GETBIT(marked_vertices, v0)){
+			if(!GETBIT(marked_vertices,v1))
+			{
+				SETVALUE1(bdz->g, v1, UNASSIGNED); 
+				SETBIT(marked_vertices, v1);
+			}
+			if(!GETBIT(marked_vertices,v2))
+			{
+				SETVALUE1(bdz->g, v2, UNASSIGNED);		
+				SETBIT(marked_vertices, v2);
+			}
+			SETVALUE1(bdz->g, v0, (6-(GETVALUE(bdz->g, v1) + GETVALUE(bdz->g,v2)))%3);
+			SETBIT(marked_vertices, v0);
+		} else if(!GETBIT(marked_vertices, v1)) {
+			if(!GETBIT(marked_vertices, v2))
+			{
+				SETVALUE1(bdz->g, v2, UNASSIGNED);
+				SETBIT(marked_vertices, v2);
+			}
+			SETVALUE1(bdz->g, v1, (7-(GETVALUE(bdz->g, v0)+GETVALUE(bdz->g, v2)))%3);
+			SETBIT(marked_vertices, v1);
+		}else {
+			SETVALUE1(bdz->g, v2, (8-(GETVALUE(bdz->g,v0)+GETVALUE(bdz->g, v1)))%3);
+			SETBIT(marked_vertices, v2);
+		}		
+		DEBUGP("A:%u %u %u -- %u %u %u\n", v0, v1, v2, GETVALUE(bdz->g, v0), GETVALUE(bdz->g, v1), GETVALUE(bdz->g, v2));
+	};
+	free(marked_vertices);
+}
+
+
+static void ranking(bdz_config_data_t *bdz)
+{
+	cmph_uint32 i, j, offset = 0U, count = 0U, size = (bdz->k >> 2U), nbytes_total = (cmph_uint32)ceil(bdz->n/4.0), nbytes;
+	bdz->ranktable = (cmph_uint32 *)calloc((size_t)bdz->ranktablesize, sizeof(cmph_uint32));
+	// ranktable computation
+	bdz->ranktable[0] = 0;	
+	i = 1;
+	while(1)
+	{
+		if(i == bdz->ranktablesize) break;
+		nbytes = size < nbytes_total? size : nbytes_total;
+		for(j = 0; j < nbytes; j++)
+		{
+			count += bdz_lookup_table[*(bdz->g + offset + j)];
+		}
+		bdz->ranktable[i] = count;
+		offset += nbytes;
+		nbytes_total -= size;
+		i++;
+	}
+}
+
+
+int bdz_dump(cmph_t *mphf, FILE *fd)
+{
+	char *buf = NULL;
+	cmph_uint32 buflen;
+	register size_t nbytes;
+	bdz_data_t *data = (bdz_data_t *)mphf->data;
+	__cmph_dump(mphf, fd);
+
+	hash_state_dump(data->hl, &buf, &buflen);
+	DEBUGP("Dumping hash state with %u bytes to disk\n", buflen);
+	nbytes = fwrite(&buflen, sizeof(cmph_uint32), (size_t)1, fd);
+	nbytes = fwrite(buf, (size_t)buflen, (size_t)1, fd);
+	free(buf);
+
+	nbytes = fwrite(&(data->n), sizeof(cmph_uint32), (size_t)1, fd);
+	nbytes = fwrite(&(data->m), sizeof(cmph_uint32), (size_t)1, fd);
+	nbytes = fwrite(&(data->r), sizeof(cmph_uint32), (size_t)1, fd);
+	
+	cmph_uint32 sizeg = (cmph_uint32)ceil(data->n/4.0);
+	nbytes = fwrite(data->g, sizeof(cmph_uint8)*sizeg, (size_t)1, fd);
+
+	nbytes = fwrite(&(data->k), sizeof(cmph_uint32), (size_t)1, fd);
+	nbytes = fwrite(&(data->b), sizeof(cmph_uint8), (size_t)1, fd);
+	nbytes = fwrite(&(data->ranktablesize), sizeof(cmph_uint32), (size_t)1, fd);
+
+	nbytes = fwrite(data->ranktable, sizeof(cmph_uint32)*(data->ranktablesize), (size_t)1, fd);
+	#ifdef DEBUG
+	cmph_uint32 i;
+	fprintf(stderr, "G: ");
+	for (i = 0; i < data->n; ++i) fprintf(stderr, "%u ", GETVALUE(data->g, i));
+	fprintf(stderr, "\n");
+	#endif
+	return 1;
+}
+
+void bdz_load(FILE *f, cmph_t *mphf)
+{
+	char *buf = NULL;
+	cmph_uint32 buflen, sizeg;
+	register size_t nbytes;
+	bdz_data_t *bdz = (bdz_data_t *)malloc(sizeof(bdz_data_t));
+
+	DEBUGP("Loading bdz mphf\n");
+	mphf->data = bdz;
+
+	nbytes = fread(&buflen, sizeof(cmph_uint32), (size_t)1, f);
+	DEBUGP("Hash state has %u bytes\n", buflen);
+	buf = (char *)malloc((size_t)buflen);
+	nbytes = fread(buf, (size_t)buflen, (size_t)1, f);
+	bdz->hl = hash_state_load(buf, buflen);
+	free(buf);
+	
+
+	DEBUGP("Reading m and n\n");
+	nbytes = fread(&(bdz->n), sizeof(cmph_uint32), (size_t)1, f);	
+	nbytes = fread(&(bdz->m), sizeof(cmph_uint32), (size_t)1, f);	
+	nbytes = fread(&(bdz->r), sizeof(cmph_uint32), (size_t)1, f);	
+	sizeg = (cmph_uint32)ceil(bdz->n/4.0);
+	bdz->g = (cmph_uint8 *)calloc((size_t)(sizeg), sizeof(cmph_uint8));
+	nbytes = fread(bdz->g, sizeg*sizeof(cmph_uint8), (size_t)1, f);
+
+	nbytes = fread(&(bdz->k), sizeof(cmph_uint32), (size_t)1, f);
+	nbytes = fread(&(bdz->b), sizeof(cmph_uint8), (size_t)1, f);
+	nbytes = fread(&(bdz->ranktablesize), sizeof(cmph_uint32), (size_t)1, f);
+
+	bdz->ranktable = (cmph_uint32 *)calloc((size_t)bdz->ranktablesize, sizeof(cmph_uint32));
+	nbytes = fread(bdz->ranktable, sizeof(cmph_uint32)*(bdz->ranktablesize), (size_t)1, f);
+
+	#ifdef DEBUG
+	cmph_uint32  i = 0;
+	fprintf(stderr, "G: ");
+	for (i = 0; i < bdz->n; ++i) fprintf(stderr, "%u ", GETVALUE(bdz->g,i));
+	fprintf(stderr, "\n");
+	#endif
+	return;
+}
+		
+
+cmph_uint32 bdz_search_ph(cmph_t *mphf, const char *key, cmph_uint32 keylen)
+{
+	bdz_data_t *bdz = mphf->data;
+	cmph_uint32 hl[3];
+	hash_vector(bdz->hl, key, keylen, hl);
+	cmph_uint32 vertex;
+	hl[0] = hl[0] % bdz->r;
+	hl[1] = hl[1] % bdz->r + bdz->r;
+	hl[2] = hl[2] % bdz->r + (bdz->r << 1);
+	vertex = hl[(GETVALUE(bdz->g, hl[0]) + GETVALUE(bdz->g, hl[1]) + GETVALUE(bdz->g, hl[2])) % 3];
+	return vertex;
+}
+
+static inline cmph_uint32 rank(cmph_uint32 b, cmph_uint32 * ranktable, cmph_uint8 * g, cmph_uint32 vertex)
+{
+	register cmph_uint32 index = vertex >> b;
+	register cmph_uint32 base_rank = ranktable[index];
+	register cmph_uint32 beg_idx_v = index << b;
+	register cmph_uint32 beg_idx_b = beg_idx_v >> 2;
+	register cmph_uint32 end_idx_b = vertex >> 2;
+	while(beg_idx_b < end_idx_b)
+	{
+		base_rank += bdz_lookup_table[*(g + beg_idx_b++)];
+		
+	}
+	beg_idx_v = beg_idx_b << 2;
+	while(beg_idx_v < vertex) 
+	{
+		if(GETVALUE(g, beg_idx_v) != UNASSIGNED) base_rank++;
+		beg_idx_v++;
+	}
+	
+	return base_rank;
+}
+
+cmph_uint32 bdz_search(cmph_t *mphf, const char *key, cmph_uint32 keylen)
+{
+	register cmph_uint32 vertex;
+	register bdz_data_t *bdz = mphf->data;
+	cmph_uint32 hl[3];
+	hash_vector(bdz->hl, key, keylen, hl);
+	hl[0] = hl[0] % bdz->r;
+	hl[1] = hl[1] % bdz->r + bdz->r;
+	hl[2] = hl[2] % bdz->r + (bdz->r << 1);
+	vertex = hl[(GETVALUE(bdz->g, hl[0]) + GETVALUE(bdz->g, hl[1]) + GETVALUE(bdz->g, hl[2])) % 3];
+	return rank(bdz->b, bdz->ranktable, bdz->g, vertex);
+}
+
+
+void bdz_destroy(cmph_t *mphf)
+{
+	bdz_data_t *data = (bdz_data_t *)mphf->data;
+	free(data->g);	
+	hash_state_destroy(data->hl);
+	free(data->ranktable);
+	free(data);
+	free(mphf);
+}
+
+/** \fn void bdz_pack(cmph_t *mphf, void *packed_mphf);
+ *  \brief Support the ability to pack a perfect hash function into a preallocated contiguous memory space pointed by packed_mphf.
+ *  \param mphf pointer to the resulting mphf
+ *  \param packed_mphf pointer to the contiguous memory area used to store the resulting mphf. The size of packed_mphf must be at least cmph_packed_size() 
+ */
+void bdz_pack(cmph_t *mphf, void *packed_mphf)
+{
+	bdz_data_t *data = (bdz_data_t *)mphf->data;
+	cmph_uint8 * ptr = packed_mphf;
+
+	// packing hl type
+	CMPH_HASH hl_type = hash_get_type(data->hl);
+	*((cmph_uint32 *) ptr) = hl_type;
+	ptr += sizeof(cmph_uint32);
+
+	// packing hl
+	hash_state_pack(data->hl, ptr);
+	ptr += hash_state_packed_size(hl_type);
+
+	// packing r
+	*((cmph_uint32 *) ptr) = data->r;
+	ptr += sizeof(data->r);
+
+	// packing ranktablesize
+	*((cmph_uint32 *) ptr) = data->ranktablesize;
+	ptr += sizeof(data->ranktablesize);
+
+	// packing ranktable
+	memcpy(ptr, data->ranktable, sizeof(cmph_uint32)*(data->ranktablesize));
+	ptr += sizeof(cmph_uint32)*(data->ranktablesize);
+
+	// packing b
+	*ptr++ = data->b;
+
+	// packing g
+	cmph_uint32 sizeg = (cmph_uint32)ceil(data->n/4.0);
+	memcpy(ptr, data->g,  sizeof(cmph_uint8)*sizeg);
+}
+
+/** \fn cmph_uint32 bdz_packed_size(cmph_t *mphf);
+ *  \brief Return the amount of space needed to pack mphf.
+ *  \param mphf pointer to a mphf
+ *  \return the size of the packed function or zero for failures
+ */ 
+cmph_uint32 bdz_packed_size(cmph_t *mphf)
+{
+	bdz_data_t *data = (bdz_data_t *)mphf->data;
+
+	CMPH_HASH hl_type = hash_get_type(data->hl); 
+
+	return (cmph_uint32)(sizeof(CMPH_ALGO) + hash_state_packed_size(hl_type) + 3*sizeof(cmph_uint32) + sizeof(cmph_uint32)*(data->ranktablesize) + sizeof(cmph_uint8) + sizeof(cmph_uint8)* (cmph_uint32)(ceil(data->n/4.0)));
+}
+
+/** cmph_uint32 bdz_search(void *packed_mphf, const char *key, cmph_uint32 keylen);
+ *  \brief Use the packed mphf to do a search. 
+ *  \param  packed_mphf pointer to the packed mphf
+ *  \param key key to be hashed
+ *  \param keylen key legth in bytes
+ *  \return The mphf value
+ */
+cmph_uint32 bdz_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen)
+{
+	
+	register cmph_uint32 vertex;
+	register CMPH_HASH hl_type  = *(cmph_uint32 *)packed_mphf;
+	register cmph_uint8 *hl_ptr = (cmph_uint8 *)(packed_mphf) + 4;
+
+	register cmph_uint32 *ranktable = (cmph_uint32*)(hl_ptr + hash_state_packed_size(hl_type));
+	
+	register cmph_uint32 r = *ranktable++;
+	register cmph_uint32 ranktablesize = *ranktable++;
+	register cmph_uint8 * g = (cmph_uint8 *)(ranktable + ranktablesize);
+	register cmph_uint8 b = *g++;
+
+	cmph_uint32 hl[3];
+	hash_vector_packed(hl_ptr, hl_type, key, keylen, hl);
+	hl[0] = hl[0] % r;
+	hl[1] = hl[1] % r + r;
+	hl[2] = hl[2] % r + (r << 1);
+	vertex = hl[(GETVALUE(g, hl[0]) + GETVALUE(g, hl[1]) + GETVALUE(g, hl[2])) % 3];
+	return rank(b, ranktable, g, vertex);
+}
diff --git a/girepository/cmph/bdz.h b/girepository/cmph/bdz.h
new file mode 100755
index 0000000..f2b7b89
--- /dev/null
+++ b/girepository/cmph/bdz.h
@@ -0,0 +1,43 @@
+#ifndef __CMPH_BDZ_H__
+#define __CMPH_BDZ_H__
+
+#include "cmph.h"
+
+typedef struct __bdz_data_t bdz_data_t;
+typedef struct __bdz_config_data_t bdz_config_data_t;
+
+bdz_config_data_t *bdz_config_new();
+void bdz_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs);
+void bdz_config_destroy(cmph_config_t *mph);
+void bdz_config_set_b(cmph_config_t *mph, cmph_uint32 b);
+cmph_t *bdz_new(cmph_config_t *mph, double c);
+
+void bdz_load(FILE *f, cmph_t *mphf);
+int bdz_dump(cmph_t *mphf, FILE *f);
+void bdz_destroy(cmph_t *mphf);
+cmph_uint32 bdz_search(cmph_t *mphf, const char *key, cmph_uint32 keylen);
+
+/** \fn void bdz_pack(cmph_t *mphf, void *packed_mphf);
+ *  \brief Support the ability to pack a perfect hash function into a preallocated contiguous memory space pointed by packed_mphf.
+ *  \param mphf pointer to the resulting mphf
+ *  \param packed_mphf pointer to the contiguous memory area used to store the resulting mphf. The size of packed_mphf must be at least cmph_packed_size() 
+ */
+void bdz_pack(cmph_t *mphf, void *packed_mphf);
+
+/** \fn cmph_uint32 bdz_packed_size(cmph_t *mphf);
+ *  \brief Return the amount of space needed to pack mphf.
+ *  \param mphf pointer to a mphf
+ *  \return the size of the packed function or zero for failures
+ */ 
+cmph_uint32 bdz_packed_size(cmph_t *mphf);
+
+/** cmph_uint32 bdz_search(void *packed_mphf, const char *key, cmph_uint32 keylen);
+ *  \brief Use the packed mphf to do a search. 
+ *  \param  packed_mphf pointer to the packed mphf
+ *  \param key key to be hashed
+ *  \param keylen key legth in bytes
+ *  \return The mphf value
+ */
+cmph_uint32 bdz_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen);
+
+#endif
diff --git a/girepository/cmph/bdz_gen_lookup_table.c b/girepository/cmph/bdz_gen_lookup_table.c
new file mode 100755
index 0000000..b8f6606
--- /dev/null
+++ b/girepository/cmph/bdz_gen_lookup_table.c
@@ -0,0 +1,33 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+void help(char * prname)
+{
+	fprintf(stderr, "USE: %s <n><wordsizeinbits>\n", prname);
+	exit(1);
+}
+
+int main(int argc, char ** argv)
+{
+	if(argc != 3) help(argv[0]);
+	int n = atoi(argv[1]);
+	int wordsize = (atoi(argv[2]) >> 1);
+	int i, j, n_assigned;
+	for(i = 0; i < n; i++)
+	{
+		int num = i;
+		n_assigned = 0;
+		for(j = 0; j < wordsize; j++)
+		{			
+			if ((num & 0x0003) != 3) 
+			{
+				n_assigned++;
+				//fprintf(stderr, "num:%d\n", num);
+			}
+			num = num >> 2;
+		}
+		if(i%16 == 0) fprintf(stderr, "\n");
+		fprintf(stderr, "%d, ", n_assigned);	
+	} 
+	fprintf(stderr, "\n");
+}
diff --git a/girepository/cmph/bdz_ph.c b/girepository/cmph/bdz_ph.c
new file mode 100755
index 0000000..49cf564
--- /dev/null
+++ b/girepository/cmph/bdz_ph.c
@@ -0,0 +1,621 @@
+#include "bdz_ph.h"
+#include "cmph_structs.h"
+#include "bdz_structs_ph.h"
+#include "hash.h"
+#include "bitbool.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+//#define DEBUG
+#include "debug.h"
+#define UNASSIGNED 3
+#define NULL_EDGE 0xffffffff
+
+
+static cmph_uint8 pow3_table[5] = {1,3,9,27,81};
+static cmph_uint8 lookup_table[5][256] = {
+ {0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0},
+ {0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+};
+
+typedef struct 
+{
+	cmph_uint32 vertices[3];
+	cmph_uint32 next_edges[3];
+}bdz_ph_edge_t;
+
+typedef cmph_uint32 * bdz_ph_queue_t;
+
+static void bdz_ph_alloc_queue(bdz_ph_queue_t * queuep, cmph_uint32 nedges)
+{
+	(*queuep)=malloc(nedges*sizeof(cmph_uint32));
+};
+static void bdz_ph_free_queue(bdz_ph_queue_t * queue)
+{
+	free(*queue);
+};
+
+typedef struct 
+{
+	cmph_uint32 nedges;
+	bdz_ph_edge_t * edges;
+	cmph_uint32 * first_edge;
+	cmph_uint8 * vert_degree;	
+}bdz_ph_graph3_t;
+
+
+static void bdz_ph_alloc_graph3(bdz_ph_graph3_t * graph3, cmph_uint32 nedges, cmph_uint32 nvertices)
+{
+	graph3->edges=malloc(nedges*sizeof(bdz_ph_edge_t));
+	graph3->first_edge=malloc(nvertices*sizeof(cmph_uint32));
+	graph3->vert_degree=malloc((size_t)nvertices);	
+};
+static void bdz_ph_init_graph3(bdz_ph_graph3_t * graph3, cmph_uint32 nedges, cmph_uint32 nvertices)
+{
+	memset(graph3->first_edge,0xff,nvertices*sizeof(cmph_uint32));
+	memset(graph3->vert_degree,0,(size_t)nvertices);
+	graph3->nedges=0;
+};
+static void bdz_ph_free_graph3(bdz_ph_graph3_t *graph3)
+{
+	free(graph3->edges);
+	free(graph3->first_edge);
+	free(graph3->vert_degree);
+};
+
+static void bdz_ph_partial_free_graph3(bdz_ph_graph3_t *graph3)
+{
+	free(graph3->first_edge);
+	free(graph3->vert_degree);
+	graph3->first_edge = NULL;
+	graph3->vert_degree = NULL;
+};
+
+static void bdz_ph_add_edge(bdz_ph_graph3_t * graph3, cmph_uint32 v0, cmph_uint32 v1, cmph_uint32 v2)
+{
+	graph3->edges[graph3->nedges].vertices[0]=v0;
+	graph3->edges[graph3->nedges].vertices[1]=v1;
+	graph3->edges[graph3->nedges].vertices[2]=v2;
+	graph3->edges[graph3->nedges].next_edges[0]=graph3->first_edge[v0];
+	graph3->edges[graph3->nedges].next_edges[1]=graph3->first_edge[v1];
+	graph3->edges[graph3->nedges].next_edges[2]=graph3->first_edge[v2];
+	graph3->first_edge[v0]=graph3->first_edge[v1]=graph3->first_edge[v2]=graph3->nedges;
+	graph3->vert_degree[v0]++;
+	graph3->vert_degree[v1]++;
+	graph3->vert_degree[v2]++;
+	graph3->nedges++;
+};
+
+static void bdz_ph_dump_graph(bdz_ph_graph3_t* graph3, cmph_uint32 nedges, cmph_uint32 nvertices)
+{
+	int i;
+	for(i=0;i<nedges;i++){
+		printf("\nedge %d %d %d %d ",i,graph3->edges[i].vertices[0],
+			graph3->edges[i].vertices[1],graph3->edges[i].vertices[2]);
+		printf(" nexts %d %d %d",graph3->edges[i].next_edges[0],
+				graph3->edges[i].next_edges[1],graph3->edges[i].next_edges[2]);
+	};
+	
+	for(i=0;i<nvertices;i++){
+		printf("\nfirst for vertice %d %d ",i,graph3->first_edge[i]);
+	
+	};
+};
+
+static void bdz_ph_remove_edge(bdz_ph_graph3_t * graph3, cmph_uint32 curr_edge)
+{
+	cmph_uint32 i,j=0,vert,edge1,edge2;
+	for(i=0;i<3;i++){
+		vert=graph3->edges[curr_edge].vertices[i];
+		edge1=graph3->first_edge[vert];
+		edge2=NULL_EDGE;
+		while(edge1!=curr_edge&&edge1!=NULL_EDGE){
+			edge2=edge1;
+			if(graph3->edges[edge1].vertices[0]==vert){
+				j=0;
+			} else if(graph3->edges[edge1].vertices[1]==vert){
+				j=1;
+			} else 
+				j=2;
+			edge1=graph3->edges[edge1].next_edges[j];
+		};
+		if(edge1==NULL_EDGE){
+			printf("\nerror remove edge %d dump graph",curr_edge);
+			bdz_ph_dump_graph(graph3,graph3->nedges,graph3->nedges+graph3->nedges/4);
+			exit(-1);
+		};
+		
+		if(edge2!=NULL_EDGE){
+			graph3->edges[edge2].next_edges[j] = 
+				graph3->edges[edge1].next_edges[i];
+		} else 
+			graph3->first_edge[vert]=
+				graph3->edges[edge1].next_edges[i];
+		graph3->vert_degree[vert]--;
+	};
+	
+};
+
+static int bdz_ph_generate_queue(cmph_uint32 nedges, cmph_uint32 nvertices, bdz_ph_queue_t queue, bdz_ph_graph3_t* graph3)
+{
+	cmph_uint32 i,v0,v1,v2;
+	cmph_uint32 queue_head=0,queue_tail=0;
+	cmph_uint32 curr_edge;
+	cmph_uint32 tmp_edge;
+	cmph_uint8 * marked_edge =malloc((size_t)(nedges >> 3) + 1);
+	memset(marked_edge, 0, (size_t)(nedges >> 3) + 1);
+
+	for(i=0;i<nedges;i++){
+		v0=graph3->edges[i].vertices[0];
+		v1=graph3->edges[i].vertices[1];
+		v2=graph3->edges[i].vertices[2];
+		if(graph3->vert_degree[v0]==1 || 
+				graph3->vert_degree[v1]==1 ||
+				graph3->vert_degree[v2]==1){
+			if(!GETBIT(marked_edge,i)) {
+				queue[queue_head++]=i;
+				SETBIT(marked_edge,i);
+			}
+		};
+	};
+	while(queue_tail!=queue_head){
+		curr_edge=queue[queue_tail++];
+		bdz_ph_remove_edge(graph3,curr_edge);
+		v0=graph3->edges[curr_edge].vertices[0];
+		v1=graph3->edges[curr_edge].vertices[1];
+		v2=graph3->edges[curr_edge].vertices[2];
+		if(graph3->vert_degree[v0]==1 ) {
+			tmp_edge=graph3->first_edge[v0];
+			if(!GETBIT(marked_edge,tmp_edge)) {
+				queue[queue_head++]=tmp_edge;
+				SETBIT(marked_edge,tmp_edge);
+			};
+			
+		};
+		if(graph3->vert_degree[v1]==1) {
+			tmp_edge=graph3->first_edge[v1];
+			if(!GETBIT(marked_edge,tmp_edge)){
+				queue[queue_head++]=tmp_edge;
+				SETBIT(marked_edge,tmp_edge);
+			};
+			
+		};
+		if(graph3->vert_degree[v2]==1){
+			tmp_edge=graph3->first_edge[v2];
+			if(!GETBIT(marked_edge,tmp_edge)){
+				queue[queue_head++]=tmp_edge;
+				SETBIT(marked_edge,tmp_edge);
+			};
+		};
+	};
+	free(marked_edge);
+	return (int)queue_head - (int)nedges;/* returns 0 if successful otherwies return negative number*/
+};
+
+static int bdz_ph_mapping(cmph_config_t *mph, bdz_ph_graph3_t* graph3, bdz_ph_queue_t queue);
+static void assigning(bdz_ph_config_data_t *bdz_ph, bdz_ph_graph3_t* graph3, bdz_ph_queue_t queue);
+static void bdz_ph_optimization(bdz_ph_config_data_t *bdz_ph);
+
+bdz_ph_config_data_t *bdz_ph_config_new()
+{
+	bdz_ph_config_data_t *bdz_ph;
+	bdz_ph = (bdz_ph_config_data_t *)malloc(sizeof(bdz_ph_config_data_t));
+	assert(bdz_ph);
+	memset(bdz_ph, 0, sizeof(bdz_ph_config_data_t));
+	bdz_ph->hashfunc = CMPH_HASH_JENKINS;
+	bdz_ph->g = NULL;
+	bdz_ph->hl = NULL;
+	return bdz_ph;
+}
+
+void bdz_ph_config_destroy(cmph_config_t *mph)
+{
+	bdz_ph_config_data_t *data = (bdz_ph_config_data_t *)mph->data;
+	DEBUGP("Destroying algorithm dependent data\n");
+	free(data);
+}
+
+void bdz_ph_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs)
+{
+	bdz_ph_config_data_t *bdz_ph = (bdz_ph_config_data_t *)mph->data;
+	CMPH_HASH *hashptr = hashfuncs;
+	cmph_uint32 i = 0;
+	while(*hashptr != CMPH_HASH_COUNT)
+	{
+		if (i >= 1) break; //bdz_ph only uses one linear hash function
+		bdz_ph->hashfunc = *hashptr;	
+		++i, ++hashptr;
+	}
+}
+
+cmph_t *bdz_ph_new(cmph_config_t *mph, double c)
+{
+	cmph_t *mphf = NULL;
+	bdz_ph_data_t *bdz_phf = NULL;
+	cmph_uint32 iterations;
+	bdz_ph_queue_t edges;
+	bdz_ph_graph3_t graph3;
+	bdz_ph_config_data_t *bdz_ph = (bdz_ph_config_data_t *)mph->data;
+	#ifdef CMPH_TIMING
+	double construction_time_begin = 0.0;
+	double construction_time = 0.0;
+	ELAPSED_TIME_IN_SECONDS(&construction_time_begin);
+	#endif
+
+
+	if (c == 0) c = 1.23; // validating restrictions over parameter c.
+	DEBUGP("c: %f\n", c);
+	bdz_ph->m = mph->key_source->nkeys;	
+	bdz_ph->r = (cmph_uint32)ceil((c * mph->key_source->nkeys)/3);	
+	if ((bdz_ph->r % 2) == 0) bdz_ph->r += 1;
+	bdz_ph->n = 3*bdz_ph->r;
+
+	
+	bdz_ph_alloc_graph3(&graph3, bdz_ph->m, bdz_ph->n);
+	bdz_ph_alloc_queue(&edges,bdz_ph->m);
+	DEBUGP("Created hypergraph\n");
+	
+	DEBUGP("m (edges): %u n (vertices): %u  r: %u c: %f \n", bdz_ph->m, bdz_ph->n, bdz_ph->r, c);
+
+	// Mapping step
+	iterations = 100;
+	if (mph->verbosity)
+	{
+		fprintf(stderr, "Entering mapping step for mph creation of %u keys with graph sized %u\n", bdz_ph->m, bdz_ph->n);
+	}
+	while(1)
+	{
+		int ok;
+		DEBUGP("linear hash function \n");
+		bdz_ph->hl = hash_state_new(bdz_ph->hashfunc, 15);
+
+		ok = bdz_ph_mapping(mph, &graph3, edges);
+		if (!ok)
+		{
+			--iterations;
+			hash_state_destroy(bdz_ph->hl);
+			bdz_ph->hl = NULL;
+			DEBUGP("%u iterations remaining\n", iterations);
+			if (mph->verbosity)
+			{
+				fprintf(stderr, "acyclic graph creation failure - %u iterations remaining\n", iterations);
+			}
+			if (iterations == 0) break;
+		} 
+		else break;
+	}
+	
+	if (iterations == 0)
+	{
+//		free(bdz_ph->g);
+		bdz_ph_free_queue(&edges);
+		bdz_ph_free_graph3(&graph3);
+		return NULL;
+	}
+	bdz_ph_partial_free_graph3(&graph3);
+	// Assigning step
+	if (mph->verbosity)
+	{
+		fprintf(stderr, "Entering assigning step for mph creation of %u keys with graph sized %u\n", bdz_ph->m, bdz_ph->n);
+	}
+	assigning(bdz_ph, &graph3, edges);
+
+	bdz_ph_free_queue(&edges);
+	bdz_ph_free_graph3(&graph3);
+	
+	if (mph->verbosity)
+	{
+		fprintf(stderr, "Starting optimization step\n");
+	}
+
+	bdz_ph_optimization(bdz_ph);
+
+	#ifdef CMPH_TIMING
+	ELAPSED_TIME_IN_SECONDS(&construction_time);
+	#endif
+	mphf = (cmph_t *)malloc(sizeof(cmph_t));
+	mphf->algo = mph->algo;
+	bdz_phf = (bdz_ph_data_t *)malloc(sizeof(bdz_ph_data_t));
+	bdz_phf->g = bdz_ph->g;
+	bdz_ph->g = NULL; //transfer memory ownership
+	bdz_phf->hl = bdz_ph->hl;
+	bdz_ph->hl = NULL; //transfer memory ownership
+	bdz_phf->n = bdz_ph->n;
+	bdz_phf->m = bdz_ph->m;
+	bdz_phf->r = bdz_ph->r;
+	mphf->data = bdz_phf;
+	mphf->size = bdz_ph->n;
+
+	DEBUGP("Successfully generated minimal perfect hash\n");
+	if (mph->verbosity)
+	{
+		fprintf(stderr, "Successfully generated minimal perfect hash function\n");
+	}
+
+	#ifdef CMPH_TIMING	
+	register cmph_uint32 space_usage = bdz_ph_packed_size(mphf)*8;
+	register cmph_uint32 keys_per_bucket = 1;
+	construction_time = construction_time - construction_time_begin;
+	fprintf(stdout, "%u\t%.2f\t%u\t%.4f\t%.4f\n", bdz_ph->m, bdz_ph->m/(double)bdz_ph->n, keys_per_bucket, construction_time, space_usage/(double)bdz_ph->m);
+	#endif	
+
+	return mphf;
+}
+
+		
+static int bdz_ph_mapping(cmph_config_t *mph, bdz_ph_graph3_t* graph3, bdz_ph_queue_t queue)
+{
+	cmph_uint32 e;
+	int cycles = 0;
+	cmph_uint32 hl[3];
+	
+	bdz_ph_config_data_t *bdz_ph = (bdz_ph_config_data_t *)mph->data;
+	bdz_ph_init_graph3(graph3, bdz_ph->m, bdz_ph->n);
+	mph->key_source->rewind(mph->key_source->data);
+	for (e = 0; e < mph->key_source->nkeys; ++e)
+	{
+		cmph_uint32 h0, h1, h2;
+		cmph_uint32 keylen;
+		char *key = NULL;
+		mph->key_source->read(mph->key_source->data, &key, &keylen);		
+		hash_vector(bdz_ph->hl, key, keylen, hl);
+		h0 = hl[0] % bdz_ph->r;
+		h1 = hl[1] % bdz_ph->r + bdz_ph->r;
+		h2 = hl[2] % bdz_ph->r + (bdz_ph->r << 1);
+		mph->key_source->dispose(mph->key_source->data, key, keylen);
+		bdz_ph_add_edge(graph3,h0,h1,h2);
+	}
+	cycles = bdz_ph_generate_queue(bdz_ph->m, bdz_ph->n, queue, graph3);	
+	return (cycles == 0);
+}
+
+static void assigning(bdz_ph_config_data_t *bdz_ph, bdz_ph_graph3_t* graph3, bdz_ph_queue_t queue)
+{
+	cmph_uint32 i;
+	cmph_uint32 nedges=graph3->nedges;
+	cmph_uint32 curr_edge;
+	cmph_uint32 v0,v1,v2;
+	cmph_uint8 * marked_vertices =malloc((size_t)(bdz_ph->n >> 3) + 1);
+	cmph_uint32 sizeg = (cmph_uint32)ceil(bdz_ph->n/4.0);
+	bdz_ph->g = (cmph_uint8 *)calloc((size_t)sizeg, sizeof(cmph_uint8));	
+	memset(marked_vertices, 0, (size_t)(bdz_ph->n >> 3) + 1);
+	//memset(bdz_ph->g, 0xff, sizeg);
+
+	for(i=nedges-1;i+1>=1;i--){
+		curr_edge=queue[i];
+		v0=graph3->edges[curr_edge].vertices[0];
+		v1=graph3->edges[curr_edge].vertices[1];
+		v2=graph3->edges[curr_edge].vertices[2];
+		DEBUGP("B:%u %u %u -- %u %u %u\n", v0, v1, v2, GETVALUE(bdz_ph->g, v0), GETVALUE(bdz_ph->g, v1), GETVALUE(bdz_ph->g, v2));
+		if(!GETBIT(marked_vertices, v0)){
+			if(!GETBIT(marked_vertices,v1))
+			{
+				//SETVALUE(bdz_ph->g, v1, UNASSIGNED); 
+				SETBIT(marked_vertices, v1);
+			}
+			if(!GETBIT(marked_vertices,v2))
+			{
+				//SETVALUE(bdz_ph->g, v2, UNASSIGNED);		
+				SETBIT(marked_vertices, v2);
+			}			
+			SETVALUE0(bdz_ph->g, v0, (6-(GETVALUE(bdz_ph->g, v1) + GETVALUE(bdz_ph->g,v2)))%3);
+			SETBIT(marked_vertices, v0);
+		} else if(!GETBIT(marked_vertices, v1)) {
+			if(!GETBIT(marked_vertices, v2))
+			{
+				//SETVALUE(bdz_ph->g, v2, UNASSIGNED);
+				SETBIT(marked_vertices, v2);
+			}
+			SETVALUE0(bdz_ph->g, v1, (7 - (GETVALUE(bdz_ph->g, v0)+GETVALUE(bdz_ph->g, v2)))%3);
+			SETBIT(marked_vertices, v1);
+		}else {
+			SETVALUE0(bdz_ph->g, v2, (8-(GETVALUE(bdz_ph->g,v0)+GETVALUE(bdz_ph->g, v1)))%3);
+			SETBIT(marked_vertices, v2);
+		}		
+		DEBUGP("A:%u %u %u -- %u %u %u\n", v0, v1, v2, GETVALUE(bdz_ph->g, v0), GETVALUE(bdz_ph->g, v1), GETVALUE(bdz_ph->g, v2));
+	};
+	free(marked_vertices);
+}
+
+static void bdz_ph_optimization(bdz_ph_config_data_t *bdz_ph)
+{
+	cmph_uint32 i;
+	cmph_uint8 byte = 0;
+	cmph_uint32 sizeg = (cmph_uint32)ceil(bdz_ph->n/5.0);
+	cmph_uint8 * new_g = (cmph_uint8 *)calloc((size_t)sizeg, sizeof(cmph_uint8));	
+	cmph_uint8 value;
+	cmph_uint32 idx;
+	for(i = 0; i < bdz_ph->n; i++) 
+	{	
+            idx = i/5;
+            byte = new_g[idx];
+            value = GETVALUE(bdz_ph->g, i);
+            byte = (cmph_uint8) (byte + value*pow3_table[i%5U]);
+            new_g[idx] = byte;
+        }
+	free(bdz_ph->g);
+	bdz_ph->g = new_g;
+}
+
+
+int bdz_ph_dump(cmph_t *mphf, FILE *fd)
+{
+	char *buf = NULL;
+	cmph_uint32 buflen;
+	cmph_uint32 sizeg = 0;
+	register size_t nbytes;
+	bdz_ph_data_t *data = (bdz_ph_data_t *)mphf->data;
+	__cmph_dump(mphf, fd);
+
+	hash_state_dump(data->hl, &buf, &buflen);
+	DEBUGP("Dumping hash state with %u bytes to disk\n", buflen);
+	nbytes = fwrite(&buflen, sizeof(cmph_uint32), (size_t)1, fd);
+	nbytes = fwrite(buf, (size_t)buflen, (size_t)1, fd);
+	free(buf);
+
+	nbytes = fwrite(&(data->n), sizeof(cmph_uint32), (size_t)1, fd);
+	nbytes = fwrite(&(data->m), sizeof(cmph_uint32), (size_t)1, fd);
+	nbytes = fwrite(&(data->r), sizeof(cmph_uint32), (size_t)1, fd);
+	sizeg = (cmph_uint32)ceil(data->n/5.0);	
+	nbytes = fwrite(data->g, sizeof(cmph_uint8)*sizeg, (size_t)1, fd);
+
+	#ifdef DEBUG
+	cmph_uint32 i;
+	fprintf(stderr, "G: ");
+	for (i = 0; i < data->n; ++i) fprintf(stderr, "%u ", GETVALUE(data->g, i));
+	fprintf(stderr, "\n");
+	#endif
+	return 1;
+}
+
+void bdz_ph_load(FILE *f, cmph_t *mphf)
+{
+	char *buf = NULL;
+	cmph_uint32 buflen;
+	cmph_uint32 sizeg = 0;
+	register size_t nbytes;
+	bdz_ph_data_t *bdz_ph = (bdz_ph_data_t *)malloc(sizeof(bdz_ph_data_t));
+
+	DEBUGP("Loading bdz_ph mphf\n");
+	mphf->data = bdz_ph;
+
+	nbytes = fread(&buflen, sizeof(cmph_uint32), (size_t)1, f);
+	DEBUGP("Hash state has %u bytes\n", buflen);
+	buf = (char *)malloc((size_t)buflen);
+	nbytes = fread(buf, (size_t)buflen, (size_t)1, f);
+	bdz_ph->hl = hash_state_load(buf, buflen);
+	free(buf);
+	
+
+	DEBUGP("Reading m and n\n");
+	nbytes = fread(&(bdz_ph->n), sizeof(cmph_uint32), (size_t)1, f);	
+	nbytes = fread(&(bdz_ph->m), sizeof(cmph_uint32), (size_t)1, f);	
+	nbytes = fread(&(bdz_ph->r), sizeof(cmph_uint32), (size_t)1, f);	
+	sizeg = (cmph_uint32)ceil(bdz_ph->n/5.0);
+	bdz_ph->g = (cmph_uint8 *)calloc((size_t)sizeg, sizeof(cmph_uint8));
+	nbytes = fread(bdz_ph->g, sizeg*sizeof(cmph_uint8), (size_t)1, f);
+
+	return;
+}
+		
+
+cmph_uint32 bdz_ph_search(cmph_t *mphf, const char *key, cmph_uint32 keylen)
+{
+	register bdz_ph_data_t *bdz_ph = mphf->data;
+	cmph_uint32 hl[3];
+	register cmph_uint8 byte0, byte1, byte2;
+	register cmph_uint32 vertex;
+
+	hash_vector(bdz_ph->hl, key, keylen,hl);
+	hl[0] = hl[0] % bdz_ph->r;
+	hl[1] = hl[1] % bdz_ph->r + bdz_ph->r;
+	hl[2] = hl[2] % bdz_ph->r + (bdz_ph->r << 1);
+
+	byte0 = bdz_ph->g[hl[0]/5];
+	byte1 = bdz_ph->g[hl[1]/5];
+	byte2 = bdz_ph->g[hl[2]/5];
+	
+	byte0 = lookup_table[hl[0]%5U][byte0];
+	byte1 = lookup_table[hl[1]%5U][byte1];
+	byte2 = lookup_table[hl[2]%5U][byte2];
+	vertex = hl[(byte0 + byte1 + byte2)%3];
+		
+	return vertex;
+}
+
+
+void bdz_ph_destroy(cmph_t *mphf)
+{
+	bdz_ph_data_t *data = (bdz_ph_data_t *)mphf->data;
+	free(data->g);	
+	hash_state_destroy(data->hl);
+	free(data);
+	free(mphf);
+}
+
+/** \fn void bdz_ph_pack(cmph_t *mphf, void *packed_mphf);
+ *  \brief Support the ability to pack a perfect hash function into a preallocated contiguous memory space pointed by packed_mphf.
+ *  \param mphf pointer to the resulting mphf
+ *  \param packed_mphf pointer to the contiguous memory area used to store the resulting mphf. The size of packed_mphf must be at least cmph_packed_size() 
+ */
+void bdz_ph_pack(cmph_t *mphf, void *packed_mphf)
+{
+	bdz_ph_data_t *data = (bdz_ph_data_t *)mphf->data;
+	cmph_uint8 * ptr = packed_mphf;
+
+	// packing hl type
+	CMPH_HASH hl_type = hash_get_type(data->hl);
+	*((cmph_uint32 *) ptr) = hl_type;
+	ptr += sizeof(cmph_uint32);
+
+	// packing hl
+	hash_state_pack(data->hl, ptr);
+	ptr += hash_state_packed_size(hl_type);
+
+	// packing r
+	*((cmph_uint32 *) ptr) = data->r;
+	ptr += sizeof(data->r);
+
+	// packing g
+	cmph_uint32 sizeg = (cmph_uint32)ceil(data->n/5.0);
+	memcpy(ptr, data->g,  sizeof(cmph_uint8)*sizeg);
+}
+
+/** \fn cmph_uint32 bdz_ph_packed_size(cmph_t *mphf);
+ *  \brief Return the amount of space needed to pack mphf.
+ *  \param mphf pointer to a mphf
+ *  \return the size of the packed function or zero for failures
+ */ 
+cmph_uint32 bdz_ph_packed_size(cmph_t *mphf)
+{
+	bdz_ph_data_t *data = (bdz_ph_data_t *)mphf->data;
+	CMPH_HASH hl_type = hash_get_type(data->hl); 
+	cmph_uint32 sizeg = (cmph_uint32)ceil(data->n/5.0);
+	return (cmph_uint32) (sizeof(CMPH_ALGO) + hash_state_packed_size(hl_type) + 2*sizeof(cmph_uint32) + sizeof(cmph_uint8)*sizeg);
+}
+
+/** cmph_uint32 bdz_ph_search(void *packed_mphf, const char *key, cmph_uint32 keylen);
+ *  \brief Use the packed mphf to do a search. 
+ *  \param  packed_mphf pointer to the packed mphf
+ *  \param key key to be hashed
+ *  \param keylen key legth in bytes
+ *  \return The mphf value
+ */
+cmph_uint32 bdz_ph_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen)
+{
+	
+	register CMPH_HASH hl_type  = *(cmph_uint32 *)packed_mphf;
+	register cmph_uint8 *hl_ptr = (cmph_uint8 *)(packed_mphf) + 4;
+	
+	register cmph_uint8 * ptr = hl_ptr + hash_state_packed_size(hl_type);
+
+	register cmph_uint32 r = *((cmph_uint32*) ptr);
+	register cmph_uint8 * g = ptr + 4;
+	
+	cmph_uint32 hl[3];
+	register cmph_uint8 byte0, byte1, byte2;
+	register cmph_uint32 vertex;
+
+	hash_vector_packed(hl_ptr, hl_type, key, keylen, hl);
+	
+	hl[0] = hl[0] % r;
+	hl[1] = hl[1] % r + r;
+	hl[2] = hl[2] % r + (r << 1);
+
+	byte0 = g[hl[0]/5];
+	byte1 = g[hl[1]/5];
+	byte2 = g[hl[2]/5];
+	
+	byte0 = lookup_table[hl[0]%5][byte0];
+	byte1 = lookup_table[hl[1]%5][byte1];
+	byte2 = lookup_table[hl[2]%5][byte2];
+	vertex = hl[(byte0 + byte1 + byte2)%3];
+		
+	return vertex;
+}
diff --git a/girepository/cmph/bdz_ph.h b/girepository/cmph/bdz_ph.h
new file mode 100755
index 0000000..73cce2e
--- /dev/null
+++ b/girepository/cmph/bdz_ph.h
@@ -0,0 +1,42 @@
+#ifndef __CMPH_BDZ_PH_H__
+#define __CMPH_BDZ_PH_H__
+
+#include "cmph.h"
+
+typedef struct __bdz_ph_data_t bdz_ph_data_t;
+typedef struct __bdz_ph_config_data_t bdz_ph_config_data_t;
+
+bdz_ph_config_data_t *bdz_ph_config_new();
+void bdz_ph_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs);
+void bdz_ph_config_destroy(cmph_config_t *mph);
+cmph_t *bdz_ph_new(cmph_config_t *mph, double c);
+
+void bdz_ph_load(FILE *f, cmph_t *mphf);
+int bdz_ph_dump(cmph_t *mphf, FILE *f);
+void bdz_ph_destroy(cmph_t *mphf);
+cmph_uint32 bdz_ph_search(cmph_t *mphf, const char *key, cmph_uint32 keylen);
+
+/** \fn void bdz_ph_pack(cmph_t *mphf, void *packed_mphf);
+ *  \brief Support the ability to pack a perfect hash function into a preallocated contiguous memory space pointed by packed_mphf.
+ *  \param mphf pointer to the resulting mphf
+ *  \param packed_mphf pointer to the contiguous memory area used to store the resulting mphf. The size of packed_mphf must be at least cmph_packed_size() 
+ */
+void bdz_ph_pack(cmph_t *mphf, void *packed_mphf);
+
+/** \fn cmph_uint32 bdz_ph_packed_size(cmph_t *mphf);
+ *  \brief Return the amount of space needed to pack mphf.
+ *  \param mphf pointer to a mphf
+ *  \return the size of the packed function or zero for failures
+ */ 
+cmph_uint32 bdz_ph_packed_size(cmph_t *mphf);
+
+/** cmph_uint32 bdz_ph_search(void *packed_mphf, const char *key, cmph_uint32 keylen);
+ *  \brief Use the packed mphf to do a search. 
+ *  \param  packed_mphf pointer to the packed mphf
+ *  \param key key to be hashed
+ *  \param keylen key legth in bytes
+ *  \return The mphf value
+ */
+cmph_uint32 bdz_ph_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen);
+
+#endif
diff --git a/girepository/cmph/bdz_structs.h b/girepository/cmph/bdz_structs.h
new file mode 100755
index 0000000..ba7dc3c
--- /dev/null
+++ b/girepository/cmph/bdz_structs.h
@@ -0,0 +1,36 @@
+#ifndef __CMPH_BDZ_STRUCTS_H__
+#define __CMPH_BDZ_STRUCTS_H__
+
+#include "hash_state.h"
+
+struct __bdz_data_t
+{
+	cmph_uint32 m; //edges (words) count
+	cmph_uint32 n; //vertex count
+	cmph_uint32 r; //partition vertex count
+	cmph_uint8 *g;
+	hash_state_t *hl; // linear hashing
+
+	cmph_uint32 k; //kth index in ranktable, $k = log_2(n=3r)/\varepsilon$
+	cmph_uint8 b; // number of bits of k
+	cmph_uint32 ranktablesize; //number of entries in ranktable, $n/k +1$
+	cmph_uint32 *ranktable; // rank table
+};
+
+
+struct __bdz_config_data_t
+{
+	cmph_uint32 m; //edges (words) count
+	cmph_uint32 n; //vertex count
+	cmph_uint32 r; //partition vertex count
+	cmph_uint8 *g;
+	hash_state_t *hl; // linear hashing
+
+	cmph_uint32 k; //kth index in ranktable, $k = log_2(n=3r)/\varepsilon$
+	cmph_uint8 b; // number of bits of k
+	cmph_uint32 ranktablesize; //number of entries in ranktable, $n/k +1$
+	cmph_uint32 *ranktable; // rank table
+	CMPH_HASH hashfunc;
+};
+
+#endif
diff --git a/girepository/cmph/bdz_structs_ph.h b/girepository/cmph/bdz_structs_ph.h
new file mode 100755
index 0000000..5874a26
--- /dev/null
+++ b/girepository/cmph/bdz_structs_ph.h
@@ -0,0 +1,26 @@
+#ifndef __CMPH_BDZ_STRUCTS_PH_H__
+#define __CMPH_BDZ_STRUCTS_PH_H__
+
+#include "hash_state.h"
+
+struct __bdz_ph_data_t
+{
+	cmph_uint32 m; //edges (words) count
+	cmph_uint32 n; //vertex count
+	cmph_uint32 r; //partition vertex count
+	cmph_uint8 *g;
+	hash_state_t *hl; // linear hashing
+};
+
+
+struct __bdz_ph_config_data_t
+{
+	CMPH_HASH hashfunc;
+	cmph_uint32 m; //edges (words) count
+	cmph_uint32 n; //vertex count
+	cmph_uint32 r; //partition vertex count
+	cmph_uint8 *g;
+	hash_state_t *hl; // linear hashing
+};
+
+#endif
diff --git a/girepository/cmph/bitbool.h b/girepository/cmph/bitbool.h
new file mode 100644
index 0000000..a3286c3
--- /dev/null
+++ b/girepository/cmph/bitbool.h
@@ -0,0 +1,179 @@
+#ifndef _CMPH_BITBOOL_H__
+#define _CMPH_BITBOOL_H__
+#include "cmph_types.h" 
+
+static const cmph_uint8 bitmask[] = { 1, 1 << 1,  1 << 2,  1 << 3, 1 << 4, 1 << 5, 1 << 6, 1 << 7 };
+
+static const cmph_uint32 bitmask32[] = { 1,       1 << 1,  1 << 2,  1 << 3,  1 << 4,  1 << 5,  1 << 6, 1 << 7,
+                                         1 << 8,  1 << 9,  1 << 10, 1 << 11, 1 << 12, 1 << 13, 1 << 14, 1 << 15,
+                                         1 << 16, 1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 21, 1 << 22, 1 << 23,
+                                         1 << 24, 1 << 25, 1 << 26, 1 << 27, 1 << 28, 1 << 29, 1 << 30, 1U << 31
+				       };
+
+static const cmph_uint8 valuemask[] = { 0xfc, 0xf3, 0xcf, 0x3f};
+
+
+/** \def GETBIT(array, i)
+ *  \brief get the value of an 1-bit integer stored in an array. 
+ *  \param array to get 1-bit integer values from
+ *  \param i is the index in array to get the 1-bit integer value from
+ * 
+ * GETBIT(array, i) is a macro that gets the value of an 1-bit integer stored in array.
+ */
+#define GETBIT(array, i) ((array[i >> 3] & bitmask[i & 0x00000007]) >> (i & 0x00000007))
+
+/** \def SETBIT(array, i)
+ *  \brief set 1 to an 1-bit integer stored in an array. 
+ *  \param array to store 1-bit integer values
+ *  \param i is the index in array to set the the bit to 1
+ * 
+ * SETBIT(array, i) is a macro that sets 1 to an 1-bit integer stored in an array.
+ */
+#define SETBIT(array, i) (array[i >> 3] |= bitmask[i & 0x00000007])
+
+/** \def UNSETBIT(array, i)
+ *  \brief set 0 to an 1-bit integer stored in an array. 
+ *  \param array to store 1-bit integer values
+ *  \param i is the index in array to set the the bit to 0
+ * 
+ * UNSETBIT(array, i) is a macro that sets 0 to an 1-bit integer stored in an array.
+ */
+#define UNSETBIT(array, i) (array[i >> 3] ^= ((bitmask[i & 0x00000007])))
+
+//#define GETBIT(array, i) (array[(i) / 8] & bitmask[(i) % 8])
+//#define SETBIT(array, i) (array[(i) / 8] |= bitmask[(i) % 8])
+//#define UNSETBIT(array, i) (array[(i) / 8] ^= ((bitmask[(i) % 8])))
+
+
+/** \def SETVALUE1(array, i, v)
+ *  \brief set a value for a 2-bit integer stored in an array initialized with 1s. 
+ *  \param array to store 2-bit integer values
+ *  \param i is the index in array to set the value v
+ *  \param v is the value to be set
+ * 
+ * SETVALUE1(array, i, v) is a macro that set a value for a 2-bit integer stored in an array.
+ * The array should be initialized with all bits set to 1. For example:
+ * memset(array, 0xff, arraySize);
+ */
+#define SETVALUE1(array, i, v) (array[i >> 2] &= (cmph_uint8)((v << ((i & 0x00000003) << 1)) | valuemask[i & 0x00000003]))
+
+/** \def SETVALUE0(array, i, v)
+ *  \brief set a value for a 2-bit integer stored in an array initialized with 0s. 
+ *  \param array to store 2-bit integer values
+ *  \param i is the index in array to set the value v
+ *  \param v is the value to be set
+ * 
+ * SETVALUE0(array, i, v) is a macro that set a value for a 2-bit integer stored in an array.
+ * The array should be initialized with all bits set to 0. For example:
+ * memset(array, 0, arraySize);
+ */
+#define SETVALUE0(array, i, v) (array[i >> 2] |= (cmph_uint8)(v << ((i & 0x00000003) << 1)))
+
+
+/** \def GETVALUE(array, i)
+ *  \brief get a value for a 2-bit integer stored in an array. 
+ *  \param array to get 2-bit integer values from
+ *  \param i is the index in array to get the value from
+ * 
+ * GETVALUE(array, i) is a macro that get a value for a 2-bit integer stored in an array.
+ */
+#define GETVALUE(array, i) ((cmph_uint8)((array[i >> 2] >> ((i & 0x00000003U) << 1U)) & 0x00000003U))
+
+
+
+/** \def SETBIT32(array, i)
+ *  \brief set 1 to an 1-bit integer stored in an array of 32-bit words. 
+ *  \param array to store 1-bit integer values. The entries are 32-bit words.
+ *  \param i is the index in array to set the the bit to 1
+ * 
+ * SETBIT32(array, i) is a macro that sets 1 to an 1-bit integer stored in an array of 32-bit words.
+ */
+#define SETBIT32(array, i) (array[i >> 5] |= bitmask32[i & 0x0000001f])
+
+/** \def GETBIT32(array, i)
+ *  \brief get the value of an 1-bit integer stored in an array of 32-bit words. 
+ *  \param array to get 1-bit integer values from. The entries are 32-bit words.
+ *  \param i is the index in array to get the 1-bit integer value from
+ * 
+ * GETBIT32(array, i) is a macro that gets the value of an 1-bit integer stored in an array of 32-bit words.
+ */
+#define GETBIT32(array, i) (array[i >> 5] & bitmask32[i & 0x0000001f])
+
+/** \def UNSETBIT32(array, i)
+ *  \brief set 0 to an 1-bit integer stored in an array of 32-bit words. 
+ *  \param array to store 1-bit integer values. The entries ar 32-bit words
+ *  \param i is the index in array to set the the bit to 0
+ * 
+ * UNSETBIT32(array, i) is a macro that sets 0 to an 1-bit integer stored in an array of 32-bit words.
+ */
+#define UNSETBIT32(array, i) (array[i >> 5] ^= ((bitmask32[i & 0x0000001f])))
+
+#define BITS_TABLE_SIZE(n, bits_length) ((n * bits_length + 31) >> 5)
+
+static inline void set_bits_value(cmph_uint32 * bits_table, cmph_uint32 index, cmph_uint32 bits_string, 
+                                  cmph_uint32 string_length, cmph_uint32 string_mask)
+{
+	register cmph_uint32 bit_idx = index * string_length;
+	register cmph_uint32 word_idx = bit_idx >> 5;
+	register cmph_uint32 shift1 = bit_idx & 0x0000001f;
+	register cmph_uint32 shift2 = 32 - shift1;
+	
+	bits_table[word_idx] &= ~((string_mask) << shift1);
+	bits_table[word_idx] |= bits_string << shift1;
+	
+	if(shift2 < string_length)
+	{
+		bits_table[word_idx+1] &= ~((string_mask) >> shift2);
+		bits_table[word_idx+1] |= bits_string >> shift2;
+	};
+};
+
+static inline cmph_uint32 get_bits_value(cmph_uint32 * bits_table,cmph_uint32 index, cmph_uint32 string_length, cmph_uint32 string_mask)
+{
+	register cmph_uint32 bit_idx = index * string_length;
+	register cmph_uint32 word_idx = bit_idx >> 5;
+	register cmph_uint32 shift1 = bit_idx & 0x0000001f;
+	register cmph_uint32 shift2 = 32-shift1;
+	register cmph_uint32 bits_string;
+	
+	bits_string = (bits_table[word_idx] >> shift1) & string_mask;
+	
+	if(shift2 < string_length)
+		bits_string |= (bits_table[word_idx+1] << shift2) & string_mask;
+
+	return bits_string;
+};
+
+static inline void set_bits_at_pos(cmph_uint32 * bits_table, cmph_uint32 pos, cmph_uint32 bits_string, cmph_uint32 string_length)
+{
+	register cmph_uint32 word_idx = pos >> 5;
+	register cmph_uint32 shift1 = pos & 0x0000001f;
+	register cmph_uint32 shift2 = 32-shift1;
+	register cmph_uint32 string_mask = (1U << string_length) - 1;
+	
+	bits_table[word_idx] &= ~((string_mask) << shift1);
+	bits_table[word_idx] |= bits_string << shift1;
+	if(shift2 < string_length)
+	{
+		bits_table[word_idx+1] &= ~((string_mask) >> shift2);
+		bits_table[word_idx+1] |= bits_string >> shift2;
+	}
+};
+
+static inline cmph_uint32 get_bits_at_pos(cmph_uint32 * bits_table,cmph_uint32 pos,cmph_uint32 string_length)
+{
+	register cmph_uint32 word_idx = pos >> 5;
+	register cmph_uint32 shift1 = pos & 0x0000001f;
+	register cmph_uint32 shift2 = 32 - shift1;
+	register cmph_uint32 string_mask = (1U << string_length) - 1;
+	register cmph_uint32 bits_string;
+	
+	bits_string = (bits_table[word_idx] >> shift1) & string_mask;
+
+	if(shift2 < string_length)
+		bits_string |= (bits_table[word_idx+1] << shift2) & string_mask;
+	return bits_string;
+}
+
+
+#endif
diff --git a/girepository/cmph/bmz.c b/girepository/cmph/bmz.c
new file mode 100644
index 0000000..51798a1
--- /dev/null
+++ b/girepository/cmph/bmz.c
@@ -0,0 +1,620 @@
+#include "graph.h"
+#include "bmz.h"
+#include "cmph_structs.h"
+#include "bmz_structs.h"
+#include "hash.h"
+#include "vqueue.h"
+#include "bitbool.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+
+//#define DEBUG
+#include "debug.h"
+
+static int bmz_gen_edges(cmph_config_t *mph);
+static cmph_uint8 bmz_traverse_critical_nodes(bmz_config_data_t *bmz, cmph_uint32 v, cmph_uint32 * biggest_g_value, cmph_uint32 * biggest_edge_value, cmph_uint8 * used_edges, cmph_uint8 * visited);
+static cmph_uint8 bmz_traverse_critical_nodes_heuristic(bmz_config_data_t *bmz, cmph_uint32 v, cmph_uint32 * biggest_g_value, cmph_uint32 * biggest_edge_value, cmph_uint8 * used_edges, cmph_uint8 * visited);
+static void bmz_traverse_non_critical_nodes(bmz_config_data_t *bmz, cmph_uint8 * used_edges, cmph_uint8 * visited);
+
+bmz_config_data_t *bmz_config_new()
+{
+	bmz_config_data_t *bmz = NULL;
+	bmz = (bmz_config_data_t *)malloc(sizeof(bmz_config_data_t));
+	assert(bmz);
+	memset(bmz, 0, sizeof(bmz_config_data_t));
+	bmz->hashfuncs[0] = CMPH_HASH_JENKINS;
+	bmz->hashfuncs[1] = CMPH_HASH_JENKINS;
+	bmz->g = NULL;
+	bmz->graph = NULL;
+	bmz->hashes = NULL;
+	return bmz;
+}
+
+void bmz_config_destroy(cmph_config_t *mph)
+{
+	bmz_config_data_t *data = (bmz_config_data_t *)mph->data;
+	DEBUGP("Destroying algorithm dependent data\n");
+	free(data);
+}
+
+void bmz_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs)
+{
+	bmz_config_data_t *bmz = (bmz_config_data_t *)mph->data;
+	CMPH_HASH *hashptr = hashfuncs;
+	cmph_uint32 i = 0;
+	while(*hashptr != CMPH_HASH_COUNT)
+	{
+		if (i >= 2) break; //bmz only uses two hash functions
+		bmz->hashfuncs[i] = *hashptr;	
+		++i, ++hashptr;
+	}
+}
+
+cmph_t *bmz_new(cmph_config_t *mph, double c)
+{
+	cmph_t *mphf = NULL;
+	bmz_data_t *bmzf = NULL;
+	cmph_uint32 i;
+	cmph_uint32 iterations;
+	cmph_uint32 iterations_map = 20;
+	cmph_uint8 *used_edges = NULL;
+	cmph_uint8 restart_mapping = 0;
+	cmph_uint8 * visited = NULL;
+
+	bmz_config_data_t *bmz = (bmz_config_data_t *)mph->data;
+	if (c == 0) c = 1.15; // validating restrictions over parameter c.
+	DEBUGP("c: %f\n", c);
+	bmz->m = mph->key_source->nkeys;	
+	bmz->n = (cmph_uint32)ceil(c * mph->key_source->nkeys);	
+	DEBUGP("m (edges): %u n (vertices): %u c: %f\n", bmz->m, bmz->n, c);
+	bmz->graph = graph_new(bmz->n, bmz->m);
+	DEBUGP("Created graph\n");
+
+	bmz->hashes = (hash_state_t **)malloc(sizeof(hash_state_t *)*3);
+	for(i = 0; i < 3; ++i) bmz->hashes[i] = NULL;
+
+	do
+	{
+	  // Mapping step
+	  cmph_uint32 biggest_g_value = 0;
+	  cmph_uint32 biggest_edge_value = 1;	
+	  iterations = 100;
+	  if (mph->verbosity)
+	  {
+		fprintf(stderr, "Entering mapping step for mph creation of %u keys with graph sized %u\n", bmz->m, bmz->n);
+	  }
+	  while(1)
+	  {
+		int ok;
+		DEBUGP("hash function 1\n");
+		bmz->hashes[0] = hash_state_new(bmz->hashfuncs[0], bmz->n);
+		DEBUGP("hash function 2\n");
+		bmz->hashes[1] = hash_state_new(bmz->hashfuncs[1], bmz->n);
+		DEBUGP("Generating edges\n");
+		ok = bmz_gen_edges(mph);
+		if (!ok)
+		{
+			--iterations;
+			hash_state_destroy(bmz->hashes[0]);
+			bmz->hashes[0] = NULL;
+			hash_state_destroy(bmz->hashes[1]);
+			bmz->hashes[1] = NULL;
+			DEBUGP("%u iterations remaining\n", iterations);
+			if (mph->verbosity)
+			{
+				fprintf(stderr, "simple graph creation failure - %u iterations remaining\n", iterations);
+			}
+			if (iterations == 0) break;
+		} 
+		else break;
+	  }
+	  if (iterations == 0)
+	  {
+		graph_destroy(bmz->graph);	
+		return NULL;
+	  }
+	  // Ordering step
+	  if (mph->verbosity)
+	  {
+		fprintf(stderr, "Starting ordering step\n");
+	  }
+	  graph_obtain_critical_nodes(bmz->graph);
+
+	  // Searching step
+	  if (mph->verbosity)
+	  {
+		fprintf(stderr, "Starting Searching step.\n");
+		fprintf(stderr, "\tTraversing critical vertices.\n");
+	  }
+	  DEBUGP("Searching step\n");
+	  visited = (cmph_uint8 *)malloc((size_t)bmz->n/8 + 1);
+	  memset(visited, 0, (size_t)bmz->n/8 + 1);
+	  used_edges = (cmph_uint8 *)malloc((size_t)bmz->m/8 + 1);
+	  memset(used_edges, 0, (size_t)bmz->m/8 + 1);
+	  free(bmz->g);
+	  bmz->g = (cmph_uint32 *)calloc((size_t)bmz->n, sizeof(cmph_uint32));
+	  assert(bmz->g);
+	  for (i = 0; i < bmz->n; ++i) // critical nodes
+	  {
+                if (graph_node_is_critical(bmz->graph, i) && (!GETBIT(visited,i)))
+		{
+		  if(c > 1.14) restart_mapping = bmz_traverse_critical_nodes(bmz, i, &biggest_g_value, &biggest_edge_value, used_edges, visited);
+		  else restart_mapping = bmz_traverse_critical_nodes_heuristic(bmz, i, &biggest_g_value, &biggest_edge_value, used_edges, visited);
+		  if(restart_mapping) break;
+		}
+	  }
+	  if(!restart_mapping)
+	  {
+	        if (mph->verbosity)
+	        {
+		  fprintf(stderr, "\tTraversing non critical vertices.\n");
+		}
+		bmz_traverse_non_critical_nodes(bmz, used_edges, visited); // non_critical_nodes
+	  }
+	  else 
+	  {
+ 	        iterations_map--;
+		if (mph->verbosity) fprintf(stderr, "Restarting mapping step. %u iterations remaining.\n", iterations_map);
+	  }    
+	  free(used_edges);
+	  free(visited);
+        }while(restart_mapping && iterations_map > 0);
+	graph_destroy(bmz->graph);
+	bmz->graph = NULL;
+	if (iterations_map == 0) 
+	{
+		return NULL;
+	}
+	mphf = (cmph_t *)malloc(sizeof(cmph_t));
+	mphf->algo = mph->algo;
+	bmzf = (bmz_data_t *)malloc(sizeof(bmz_data_t));
+	bmzf->g = bmz->g;
+	bmz->g = NULL; //transfer memory ownership
+	bmzf->hashes = bmz->hashes;
+	bmz->hashes = NULL; //transfer memory ownership
+	bmzf->n = bmz->n;
+	bmzf->m = bmz->m;
+	mphf->data = bmzf;
+	mphf->size = bmz->m;
+
+	DEBUGP("Successfully generated minimal perfect hash\n");
+	if (mph->verbosity)
+	{
+		fprintf(stderr, "Successfully generated minimal perfect hash function\n");
+	}
+	return mphf;
+}
+
+static cmph_uint8 bmz_traverse_critical_nodes(bmz_config_data_t *bmz, cmph_uint32 v, cmph_uint32 * biggest_g_value, cmph_uint32 * biggest_edge_value, cmph_uint8 * used_edges, cmph_uint8 * visited)
+{
+        cmph_uint32 next_g;
+	cmph_uint32 u;   /* Auxiliary vertex */
+	cmph_uint32 lav; /* lookahead vertex */
+	cmph_uint8 collision;
+	vqueue_t * q = vqueue_new((cmph_uint32)(graph_ncritical_nodes(bmz->graph)) + 1);
+	graph_iterator_t it, it1;
+
+	DEBUGP("Labelling critical vertices\n");
+	bmz->g[v] = (cmph_uint32)ceil ((double)(*biggest_edge_value)/2) - 1;
+	SETBIT(visited, v);
+	next_g    = (cmph_uint32)floor((double)(*biggest_edge_value/2)); /* next_g is incremented in the do..while statement*/
+	vqueue_insert(q, v);
+	while(!vqueue_is_empty(q))
+	{
+		v = vqueue_remove(q);
+		it = graph_neighbors_it(bmz->graph, v);		
+		while ((u = graph_next_neighbor(bmz->graph, &it)) != GRAPH_NO_NEIGHBOR)
+		{		        
+               	        if (graph_node_is_critical(bmz->graph, u) && (!GETBIT(visited,u)))
+			{
+			        collision = 1;
+			        while(collision) // lookahead to resolve collisions
+				{
+ 				        next_g = *biggest_g_value + 1; 
+					it1 = graph_neighbors_it(bmz->graph, u);
+					collision = 0;
+					while((lav = graph_next_neighbor(bmz->graph, &it1)) != GRAPH_NO_NEIGHBOR)
+					{
+  					        if (graph_node_is_critical(bmz->graph, lav) && GETBIT(visited,lav))
+						{
+   						        if(next_g + bmz->g[lav] >= bmz->m)
+							{
+							        vqueue_destroy(q);
+								return 1; // restart mapping step.
+							}
+							if (GETBIT(used_edges, (next_g + bmz->g[lav]))) 
+							{
+							        collision = 1;
+								break;
+							}
+						}
+					}
+ 					if (next_g > *biggest_g_value) *biggest_g_value = next_g;
+				}		
+				// Marking used edges...
+				it1 = graph_neighbors_it(bmz->graph, u);
+				while((lav = graph_next_neighbor(bmz->graph, &it1)) != GRAPH_NO_NEIGHBOR)
+				{
+                 		        if (graph_node_is_critical(bmz->graph, lav) && GETBIT(visited, lav))
+					{
+                   			        SETBIT(used_edges,(next_g + bmz->g[lav]));
+						if(next_g + bmz->g[lav] > *biggest_edge_value) *biggest_edge_value = next_g + bmz->g[lav];
+					}
+				}
+				bmz->g[u] = next_g; // Labelling vertex u.
+				SETBIT(visited,u);
+			        vqueue_insert(q, u);
+			}			
+	        }
+		 
+	}
+	vqueue_destroy(q);
+	return 0;
+}
+
+static cmph_uint8 bmz_traverse_critical_nodes_heuristic(bmz_config_data_t *bmz, cmph_uint32 v, cmph_uint32 * biggest_g_value, cmph_uint32 * biggest_edge_value, cmph_uint8 * used_edges, cmph_uint8 * visited)
+{
+        cmph_uint32 next_g;
+	cmph_uint32 u;   /* Auxiliary vertex */
+	cmph_uint32 lav; /* lookahead vertex */
+	cmph_uint8 collision;
+	cmph_uint32 * unused_g_values = NULL;
+	cmph_uint32 unused_g_values_capacity = 0;
+	cmph_uint32 nunused_g_values = 0;
+	vqueue_t * q = vqueue_new((cmph_uint32)(0.5*graph_ncritical_nodes(bmz->graph))+1);
+	graph_iterator_t it, it1;
+
+	DEBUGP("Labelling critical vertices\n");
+	bmz->g[v] = (cmph_uint32)ceil ((double)(*biggest_edge_value)/2) - 1;
+	SETBIT(visited, v);
+	next_g    = (cmph_uint32)floor((double)(*biggest_edge_value/2)); /* next_g is incremented in the do..while statement*/
+	vqueue_insert(q, v);
+	while(!vqueue_is_empty(q))
+	{
+		v = vqueue_remove(q);
+		it = graph_neighbors_it(bmz->graph, v);		
+		while ((u = graph_next_neighbor(bmz->graph, &it)) != GRAPH_NO_NEIGHBOR)
+		{		        
+               	        if (graph_node_is_critical(bmz->graph, u) && (!GETBIT(visited,u)))
+			{
+			        cmph_uint32 next_g_index = 0;
+			        collision = 1;
+			        while(collision) // lookahead to resolve collisions
+				{
+				        if (next_g_index < nunused_g_values) 
+					{
+					        next_g = unused_g_values[next_g_index++];						
+					}
+					else    
+					{
+					        next_g = *biggest_g_value + 1; 
+						next_g_index = UINT_MAX;
+					}
+					it1 = graph_neighbors_it(bmz->graph, u);
+					collision = 0;
+					while((lav = graph_next_neighbor(bmz->graph, &it1)) != GRAPH_NO_NEIGHBOR)
+					{
+  					        if (graph_node_is_critical(bmz->graph, lav) && GETBIT(visited,lav))
+						{
+   						        if(next_g + bmz->g[lav] >= bmz->m)
+							{
+							        vqueue_destroy(q);
+								free(unused_g_values);
+								return 1; // restart mapping step.
+							}
+							if (GETBIT(used_edges, (next_g + bmz->g[lav]))) 
+							{
+							        collision = 1;
+								break;
+							}
+						}
+					}
+					if(collision && (next_g > *biggest_g_value)) // saving the current g value stored in next_g.
+					{
+					        if(nunused_g_values == unused_g_values_capacity)
+						{
+   						        unused_g_values = (cmph_uint32 *)realloc(unused_g_values, (unused_g_values_capacity + BUFSIZ)*sizeof(cmph_uint32));
+						        unused_g_values_capacity += BUFSIZ;  							
+						} 
+						unused_g_values[nunused_g_values++] = next_g;							
+
+					}
+ 					if (next_g > *biggest_g_value) *biggest_g_value = next_g;
+				}	
+				next_g_index--;
+				if (next_g_index < nunused_g_values) unused_g_values[next_g_index] = unused_g_values[--nunused_g_values];
+
+				// Marking used edges...
+				it1 = graph_neighbors_it(bmz->graph, u);
+				while((lav = graph_next_neighbor(bmz->graph, &it1)) != GRAPH_NO_NEIGHBOR)
+				{
+                 		        if (graph_node_is_critical(bmz->graph, lav) && GETBIT(visited, lav))
+					{
+                   			        SETBIT(used_edges,(next_g + bmz->g[lav]));
+						if(next_g + bmz->g[lav] > *biggest_edge_value) *biggest_edge_value = next_g + bmz->g[lav];
+					}
+				}
+				bmz->g[u] = next_g; // Labelling vertex u.
+				SETBIT(visited, u);
+			        vqueue_insert(q, u);
+			}			
+	        }
+		 
+	}
+	vqueue_destroy(q);
+	free(unused_g_values);
+	return 0;  
+}
+
+static cmph_uint32 next_unused_edge(bmz_config_data_t *bmz, cmph_uint8 * used_edges, cmph_uint32 unused_edge_index)
+{
+       while(1)
+       {
+		assert(unused_edge_index < bmz->m);
+		if(GETBIT(used_edges, unused_edge_index)) unused_edge_index ++;
+		else break;
+       }
+       return unused_edge_index;
+}
+
+static void bmz_traverse(bmz_config_data_t *bmz, cmph_uint8 * used_edges, cmph_uint32 v, cmph_uint32 * unused_edge_index, cmph_uint8 * visited)
+{
+	graph_iterator_t it = graph_neighbors_it(bmz->graph, v);
+	cmph_uint32 neighbor = 0;
+	while((neighbor = graph_next_neighbor(bmz->graph, &it)) != GRAPH_NO_NEIGHBOR)
+	{
+     	        if(GETBIT(visited,neighbor)) continue;
+		//DEBUGP("Visiting neighbor %u\n", neighbor);
+		*unused_edge_index = next_unused_edge(bmz, used_edges, *unused_edge_index);
+		bmz->g[neighbor] = *unused_edge_index - bmz->g[v];
+		//if (bmz->g[neighbor] >= bmz->m) bmz->g[neighbor] += bmz->m;
+		SETBIT(visited, neighbor);
+		(*unused_edge_index)++;
+		bmz_traverse(bmz, used_edges, neighbor, unused_edge_index, visited);
+		
+	}  
+}
+
+static void bmz_traverse_non_critical_nodes(bmz_config_data_t *bmz, cmph_uint8 * used_edges, cmph_uint8 * visited)
+{
+
+	cmph_uint32 i, v1, v2, unused_edge_index = 0;
+	DEBUGP("Labelling non critical vertices\n");
+	for(i = 0; i < bmz->m; i++)
+	{
+	        v1 = graph_vertex_id(bmz->graph, i, 0);
+		v2 = graph_vertex_id(bmz->graph, i, 1);
+		if((GETBIT(visited,v1) && GETBIT(visited,v2)) || (!GETBIT(visited,v1) && !GETBIT(visited,v2))) continue;				  	
+		if(GETBIT(visited,v1)) bmz_traverse(bmz, used_edges, v1, &unused_edge_index, visited);
+	        else bmz_traverse(bmz, used_edges, v2, &unused_edge_index, visited);
+
+	}
+
+	for(i = 0; i < bmz->n; i++)
+	{
+		if(!GETBIT(visited,i))
+		{ 	                        
+		        bmz->g[i] = 0;
+			SETBIT(visited, i);
+			bmz_traverse(bmz, used_edges, i, &unused_edge_index, visited);
+		}
+	}
+
+}
+		
+static int bmz_gen_edges(cmph_config_t *mph)
+{
+	cmph_uint32 e;
+	bmz_config_data_t *bmz = (bmz_config_data_t *)mph->data;
+	cmph_uint8 multiple_edges = 0;
+	DEBUGP("Generating edges for %u vertices\n", bmz->n);
+	graph_clear_edges(bmz->graph);	
+	mph->key_source->rewind(mph->key_source->data);
+	for (e = 0; e < mph->key_source->nkeys; ++e)
+	{
+		cmph_uint32 h1, h2;
+		cmph_uint32 keylen;
+		char *key = NULL;
+		mph->key_source->read(mph->key_source->data, &key, &keylen);
+		
+//		if (key == NULL)fprintf(stderr, "key = %s -- read BMZ\n", key);
+		h1 = hash(bmz->hashes[0], key, keylen) % bmz->n;
+		h2 = hash(bmz->hashes[1], key, keylen) % bmz->n;
+		if (h1 == h2) if (++h2 >= bmz->n) h2 = 0;
+		if (h1 == h2) 
+		{
+			if (mph->verbosity) fprintf(stderr, "Self loop for key %u\n", e);
+			mph->key_source->dispose(mph->key_source->data, key, keylen);
+			return 0;
+		}
+		//DEBUGP("Adding edge: %u -> %u for key %s\n", h1, h2, key);
+		mph->key_source->dispose(mph->key_source->data, key, keylen);
+//		fprintf(stderr, "key = %s -- dispose BMZ\n", key);
+		multiple_edges = graph_contains_edge(bmz->graph, h1, h2);
+		if (mph->verbosity && multiple_edges) fprintf(stderr, "A non simple graph was generated\n");
+		if (multiple_edges) return 0; // checking multiple edge restriction.
+		graph_add_edge(bmz->graph, h1, h2);
+	}
+	return !multiple_edges;
+}
+
+int bmz_dump(cmph_t *mphf, FILE *fd)
+{
+	char *buf = NULL;
+	cmph_uint32 buflen;
+	cmph_uint32 two = 2; //number of hash functions
+	bmz_data_t *data = (bmz_data_t *)mphf->data;
+	register size_t nbytes;
+	__cmph_dump(mphf, fd);
+
+	nbytes = fwrite(&two, sizeof(cmph_uint32), (size_t)1, fd);
+
+	hash_state_dump(data->hashes[0], &buf, &buflen);
+	DEBUGP("Dumping hash state with %u bytes to disk\n", buflen);
+	nbytes = fwrite(&buflen, sizeof(cmph_uint32), (size_t)1, fd);
+	nbytes = fwrite(buf, (size_t)buflen, (size_t)1, fd);
+	free(buf);
+
+	hash_state_dump(data->hashes[1], &buf, &buflen);
+	DEBUGP("Dumping hash state with %u bytes to disk\n", buflen);
+	nbytes = fwrite(&buflen, sizeof(cmph_uint32), (size_t)1, fd);
+	nbytes = fwrite(buf, (size_t)buflen, (size_t)1, fd);
+	free(buf);
+
+	nbytes = fwrite(&(data->n), sizeof(cmph_uint32), (size_t)1, fd);
+	nbytes = fwrite(&(data->m), sizeof(cmph_uint32), (size_t)1, fd);
+	
+	nbytes = fwrite(data->g, sizeof(cmph_uint32)*(data->n), (size_t)1, fd);
+	#ifdef DEBUG
+	cmph_uint32 i;
+	fprintf(stderr, "G: ");
+	for (i = 0; i < data->n; ++i) fprintf(stderr, "%u ", data->g[i]);
+	fprintf(stderr, "\n");
+	#endif
+	return 1;
+}
+
+void bmz_load(FILE *f, cmph_t *mphf)
+{
+	cmph_uint32 nhashes;
+	char *buf = NULL;
+	cmph_uint32 buflen;
+	cmph_uint32 i;
+	bmz_data_t *bmz = (bmz_data_t *)malloc(sizeof(bmz_data_t));
+	register size_t nbytes;
+	DEBUGP("Loading bmz mphf\n");
+	mphf->data = bmz;
+	nbytes = fread(&nhashes, sizeof(cmph_uint32), (size_t)1, f);
+	bmz->hashes = (hash_state_t **)malloc(sizeof(hash_state_t *)*(nhashes + 1));
+	bmz->hashes[nhashes] = NULL;
+	DEBUGP("Reading %u hashes\n", nhashes);
+	for (i = 0; i < nhashes; ++i)
+	{
+		hash_state_t *state = NULL;
+		nbytes = fread(&buflen, sizeof(cmph_uint32), (size_t)1, f);
+		DEBUGP("Hash state has %u bytes\n", buflen);
+		buf = (char *)malloc((size_t)buflen);
+		nbytes = fread(buf, (size_t)buflen, (size_t)1, f);
+		state = hash_state_load(buf, buflen);
+		bmz->hashes[i] = state;
+		free(buf);
+	}
+
+	DEBUGP("Reading m and n\n");
+	nbytes = fread(&(bmz->n), sizeof(cmph_uint32), (size_t)1, f);	
+	nbytes = fread(&(bmz->m), sizeof(cmph_uint32), (size_t)1, f);	
+
+	bmz->g = (cmph_uint32 *)malloc(sizeof(cmph_uint32)*bmz->n);
+	nbytes = fread(bmz->g, bmz->n*sizeof(cmph_uint32), (size_t)1, f);
+	#ifdef DEBUG
+	fprintf(stderr, "G: ");
+	for (i = 0; i < bmz->n; ++i) fprintf(stderr, "%u ", bmz->g[i]);
+	fprintf(stderr, "\n");
+	#endif
+	return;
+}
+		
+
+cmph_uint32 bmz_search(cmph_t *mphf, const char *key, cmph_uint32 keylen)
+{
+	bmz_data_t *bmz = mphf->data;
+	cmph_uint32 h1 = hash(bmz->hashes[0], key, keylen) % bmz->n;
+	cmph_uint32 h2 = hash(bmz->hashes[1], key, keylen) % bmz->n;
+	DEBUGP("key: %s h1: %u h2: %u\n", key, h1, h2);
+	if (h1 == h2 && ++h2 > bmz->n) h2 = 0;
+	DEBUGP("key: %s g[h1]: %u g[h2]: %u edges: %u\n", key, bmz->g[h1], bmz->g[h2], bmz->m);
+	return bmz->g[h1] + bmz->g[h2];
+}
+void bmz_destroy(cmph_t *mphf)
+{
+	bmz_data_t *data = (bmz_data_t *)mphf->data;
+	free(data->g);	
+	hash_state_destroy(data->hashes[0]);
+	hash_state_destroy(data->hashes[1]);
+	free(data->hashes);
+	free(data);
+	free(mphf);
+}
+
+/** \fn void bmz_pack(cmph_t *mphf, void *packed_mphf);
+ *  \brief Support the ability to pack a perfect hash function into a preallocated contiguous memory space pointed by packed_mphf.
+ *  \param mphf pointer to the resulting mphf
+ *  \param packed_mphf pointer to the contiguous memory area used to store the resulting mphf. The size of packed_mphf must be at least cmph_packed_size() 
+ */
+void bmz_pack(cmph_t *mphf, void *packed_mphf)
+{
+
+	bmz_data_t *data = (bmz_data_t *)mphf->data;
+	cmph_uint8 * ptr = packed_mphf;
+
+	// packing h1 type
+	CMPH_HASH h1_type = hash_get_type(data->hashes[0]);
+	*((cmph_uint32 *) ptr) = h1_type;
+	ptr += sizeof(cmph_uint32);
+
+	// packing h1
+	hash_state_pack(data->hashes[0], ptr);
+	ptr += hash_state_packed_size(h1_type);
+
+	// packing h2 type
+	CMPH_HASH h2_type = hash_get_type(data->hashes[1]);
+	*((cmph_uint32 *) ptr) = h2_type;
+	ptr += sizeof(cmph_uint32);
+
+	// packing h2
+	hash_state_pack(data->hashes[1], ptr);
+	ptr += hash_state_packed_size(h2_type);
+
+	// packing n
+	*((cmph_uint32 *) ptr) = data->n;
+	ptr += sizeof(data->n);
+
+	// packing g
+	memcpy(ptr, data->g, sizeof(cmph_uint32)*data->n);	
+}
+
+/** \fn cmph_uint32 bmz_packed_size(cmph_t *mphf);
+ *  \brief Return the amount of space needed to pack mphf.
+ *  \param mphf pointer to a mphf
+ *  \return the size of the packed function or zero for failures
+ */ 
+cmph_uint32 bmz_packed_size(cmph_t *mphf)
+{
+	bmz_data_t *data = (bmz_data_t *)mphf->data;
+	CMPH_HASH h1_type = hash_get_type(data->hashes[0]); 
+	CMPH_HASH h2_type = hash_get_type(data->hashes[1]); 
+
+	return (cmph_uint32)(sizeof(CMPH_ALGO) + hash_state_packed_size(h1_type) + hash_state_packed_size(h2_type) + 
+			3*sizeof(cmph_uint32) + sizeof(cmph_uint32)*data->n);
+}
+
+/** cmph_uint32 bmz_search(void *packed_mphf, const char *key, cmph_uint32 keylen);
+ *  \brief Use the packed mphf to do a search. 
+ *  \param  packed_mphf pointer to the packed mphf
+ *  \param key key to be hashed
+ *  \param keylen key legth in bytes
+ *  \return The mphf value
+ */
+cmph_uint32 bmz_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen)
+{
+	register cmph_uint8 *h1_ptr = packed_mphf;
+	register CMPH_HASH h1_type  = *((cmph_uint32 *)h1_ptr);
+	h1_ptr += 4;
+
+	register cmph_uint8 *h2_ptr = h1_ptr + hash_state_packed_size(h1_type);
+	register CMPH_HASH h2_type  = *((cmph_uint32 *)h2_ptr);
+	h2_ptr += 4;
+	
+	register cmph_uint32 *g_ptr = (cmph_uint32 *)(h2_ptr + hash_state_packed_size(h2_type));
+	
+	register cmph_uint32 n = *g_ptr++;  
+	
+	register cmph_uint32 h1 = hash_packed(h1_ptr, h1_type, key, keylen) % n; 
+	register cmph_uint32 h2 = hash_packed(h2_ptr, h2_type, key, keylen) % n; 
+	if (h1 == h2 && ++h2 > n) h2 = 0;
+	return (g_ptr[h1] + g_ptr[h2]);	
+}
diff --git a/girepository/cmph/bmz.h b/girepository/cmph/bmz.h
new file mode 100644
index 0000000..ee5f61d
--- /dev/null
+++ b/girepository/cmph/bmz.h
@@ -0,0 +1,42 @@
+#ifndef __CMPH_BMZ_H__
+#define __CMPH_BMZ_H__
+
+#include "cmph.h"
+
+typedef struct __bmz_data_t bmz_data_t;
+typedef struct __bmz_config_data_t bmz_config_data_t;
+
+bmz_config_data_t *bmz_config_new();
+void bmz_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs);
+void bmz_config_destroy(cmph_config_t *mph);
+cmph_t *bmz_new(cmph_config_t *mph, double c);
+
+void bmz_load(FILE *f, cmph_t *mphf);
+int bmz_dump(cmph_t *mphf, FILE *f);
+void bmz_destroy(cmph_t *mphf);
+cmph_uint32 bmz_search(cmph_t *mphf, const char *key, cmph_uint32 keylen);
+
+/** \fn void bmz_pack(cmph_t *mphf, void *packed_mphf);
+ *  \brief Support the ability to pack a perfect hash function into a preallocated contiguous memory space pointed by packed_mphf.
+ *  \param mphf pointer to the resulting mphf
+ *  \param packed_mphf pointer to the contiguous memory area used to store the resulting mphf. The size of packed_mphf must be at least cmph_packed_size() 
+ */
+void bmz_pack(cmph_t *mphf, void *packed_mphf);
+
+/** \fn cmph_uint32 bmz_packed_size(cmph_t *mphf);
+ *  \brief Return the amount of space needed to pack mphf.
+ *  \param mphf pointer to a mphf
+ *  \return the size of the packed function or zero for failures
+ */ 
+cmph_uint32 bmz_packed_size(cmph_t *mphf);
+
+/** cmph_uint32 bmz_search(void *packed_mphf, const char *key, cmph_uint32 keylen);
+ *  \brief Use the packed mphf to do a search. 
+ *  \param  packed_mphf pointer to the packed mphf
+ *  \param key key to be hashed
+ *  \param keylen key legth in bytes
+ *  \return The mphf value
+ */
+cmph_uint32 bmz_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen);
+
+#endif
diff --git a/girepository/cmph/bmz8.c b/girepository/cmph/bmz8.c
new file mode 100644
index 0000000..203f4fc
--- /dev/null
+++ b/girepository/cmph/bmz8.c
@@ -0,0 +1,632 @@
+#include "graph.h"
+#include "bmz8.h"
+#include "cmph_structs.h"
+#include "bmz8_structs.h"
+#include "hash.h"
+#include "vqueue.h"
+#include "bitbool.h"
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+
+//#define DEBUG
+#include "debug.h"
+
+static int bmz8_gen_edges(cmph_config_t *mph);
+static cmph_uint8 bmz8_traverse_critical_nodes(bmz8_config_data_t *bmz8, cmph_uint32 v, cmph_uint8 * biggest_g_value, cmph_uint8 * biggest_edge_value, cmph_uint8 * used_edges, cmph_uint8 * visited);
+static cmph_uint8 bmz8_traverse_critical_nodes_heuristic(bmz8_config_data_t *bmz8, cmph_uint32 v, cmph_uint8 * biggest_g_value, cmph_uint8 * biggest_edge_value, cmph_uint8 * used_edges, cmph_uint8 * visited);
+static void bmz8_traverse_non_critical_nodes(bmz8_config_data_t *bmz8, cmph_uint8 * used_edges, cmph_uint8 * visited);
+
+bmz8_config_data_t *bmz8_config_new()
+{
+	bmz8_config_data_t *bmz8;
+	bmz8 = (bmz8_config_data_t *)malloc(sizeof(bmz8_config_data_t));
+	assert(bmz8);
+	memset(bmz8, 0, sizeof(bmz8_config_data_t));
+	bmz8->hashfuncs[0] = CMPH_HASH_JENKINS;
+	bmz8->hashfuncs[1] = CMPH_HASH_JENKINS;
+	bmz8->g = NULL;
+	bmz8->graph = NULL;
+	bmz8->hashes = NULL;
+	return bmz8;
+}
+
+void bmz8_config_destroy(cmph_config_t *mph)
+{
+	bmz8_config_data_t *data = (bmz8_config_data_t *)mph->data;
+	DEBUGP("Destroying algorithm dependent data\n");
+	free(data);
+}
+
+void bmz8_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs)
+{
+	bmz8_config_data_t *bmz8 = (bmz8_config_data_t *)mph->data;
+	CMPH_HASH *hashptr = hashfuncs;
+	cmph_uint8 i = 0;
+	while(*hashptr != CMPH_HASH_COUNT)
+	{
+		if (i >= 2) break; //bmz8 only uses two hash functions
+		bmz8->hashfuncs[i] = *hashptr;	
+		++i, ++hashptr;
+	}
+}
+
+cmph_t *bmz8_new(cmph_config_t *mph, double c)
+{
+	cmph_t *mphf = NULL;
+	bmz8_data_t *bmz8f = NULL;
+	cmph_uint8 i;
+	cmph_uint8 iterations;
+	cmph_uint8 iterations_map = 20;
+	cmph_uint8 *used_edges = NULL;
+	cmph_uint8 restart_mapping = 0;
+	cmph_uint8 * visited = NULL;
+	bmz8_config_data_t *bmz8 = (bmz8_config_data_t *)mph->data;
+	
+	if (mph->key_source->nkeys >= 256)
+	{
+		if (mph->verbosity) fprintf(stderr, "The number of keys in BMZ8 must be lower than 256.\n");
+		return NULL;
+	}
+	if (c == 0) c = 1.15; // validating restrictions over parameter c.
+	DEBUGP("c: %f\n", c);
+	bmz8->m = (cmph_uint8) mph->key_source->nkeys;	
+	bmz8->n = (cmph_uint8) ceil(c * mph->key_source->nkeys);	
+	DEBUGP("m (edges): %u n (vertices): %u c: %f\n", bmz8->m, bmz8->n, c);
+	bmz8->graph = graph_new(bmz8->n, bmz8->m);
+	DEBUGP("Created graph\n");
+
+	bmz8->hashes = (hash_state_t **)malloc(sizeof(hash_state_t *)*3);
+	for(i = 0; i < 3; ++i) bmz8->hashes[i] = NULL;
+
+	do
+	{
+	  // Mapping step
+	  cmph_uint8 biggest_g_value = 0;
+	  cmph_uint8 biggest_edge_value = 1;
+	  iterations = 100;
+	  if (mph->verbosity)
+	  {
+		fprintf(stderr, "Entering mapping step for mph creation of %u keys with graph sized %u\n", bmz8->m, bmz8->n);
+	  }
+	  while(1)
+	  {
+		int ok;
+		DEBUGP("hash function 1\n");
+		bmz8->hashes[0] = hash_state_new(bmz8->hashfuncs[0], bmz8->n);
+		DEBUGP("hash function 2\n");
+		bmz8->hashes[1] = hash_state_new(bmz8->hashfuncs[1], bmz8->n);
+		DEBUGP("Generating edges\n");
+		ok = bmz8_gen_edges(mph);
+		if (!ok)
+		{
+			--iterations;
+			hash_state_destroy(bmz8->hashes[0]);
+			bmz8->hashes[0] = NULL;
+			hash_state_destroy(bmz8->hashes[1]);
+			bmz8->hashes[1] = NULL;
+			DEBUGP("%u iterations remaining\n", iterations);
+			if (mph->verbosity)
+			{
+				fprintf(stderr, "simple graph creation failure - %u iterations remaining\n", iterations);
+			}
+			if (iterations == 0) break;
+		} 
+		else break;	
+	  }
+	  if (iterations == 0)
+	  {
+		graph_destroy(bmz8->graph);
+		return NULL;
+	  }
+
+	  // Ordering step
+	  if (mph->verbosity)
+	  {
+		fprintf(stderr, "Starting ordering step\n");
+	  }
+
+	  graph_obtain_critical_nodes(bmz8->graph);
+
+	  // Searching step
+	  if (mph->verbosity)
+	  {
+		fprintf(stderr, "Starting Searching step.\n");
+		fprintf(stderr, "\tTraversing critical vertices.\n");
+	  }
+	  DEBUGP("Searching step\n");
+	  visited = (cmph_uint8 *)malloc((size_t)bmz8->n/8 + 1);
+	  memset(visited, 0, (size_t)bmz8->n/8 + 1);
+	  used_edges = (cmph_uint8 *)malloc((size_t)bmz8->m/8 + 1);
+	  memset(used_edges, 0, (size_t)bmz8->m/8 + 1);
+	  free(bmz8->g);
+	  bmz8->g = (cmph_uint8 *)calloc((size_t)bmz8->n, sizeof(cmph_uint8));
+	  assert(bmz8->g);
+	  for (i = 0; i < bmz8->n; ++i) // critical nodes
+	  {
+                if (graph_node_is_critical(bmz8->graph, i) && (!GETBIT(visited,i)))
+		{
+		  if(c > 1.14) restart_mapping = bmz8_traverse_critical_nodes(bmz8, i, &biggest_g_value, &biggest_edge_value, used_edges, visited);
+		  else restart_mapping = bmz8_traverse_critical_nodes_heuristic(bmz8, i, &biggest_g_value, &biggest_edge_value, used_edges, visited);
+		  if(restart_mapping) break;
+		}
+	  }
+	  if(!restart_mapping)
+	  {
+	        if (mph->verbosity)
+	        {
+		  fprintf(stderr, "\tTraversing non critical vertices.\n");
+		}
+		bmz8_traverse_non_critical_nodes(bmz8, used_edges, visited); // non_critical_nodes
+	  }
+	  else 
+	  {
+ 	        iterations_map--;
+		if (mph->verbosity) fprintf(stderr, "Restarting mapping step. %u iterations remaining.\n", iterations_map);
+	  }    
+
+	  free(used_edges);
+	  free(visited);
+
+	}while(restart_mapping && iterations_map > 0);
+	graph_destroy(bmz8->graph);	
+	bmz8->graph = NULL;
+	if (iterations_map == 0) 
+	{
+		return NULL;
+	}
+	mphf = (cmph_t *)malloc(sizeof(cmph_t));
+	mphf->algo = mph->algo;
+	bmz8f = (bmz8_data_t *)malloc(sizeof(bmz8_data_t));
+	bmz8f->g = bmz8->g;
+	bmz8->g = NULL; //transfer memory ownership
+	bmz8f->hashes = bmz8->hashes;
+	bmz8->hashes = NULL; //transfer memory ownership
+	bmz8f->n = bmz8->n;
+	bmz8f->m = bmz8->m;
+	mphf->data = bmz8f;
+	mphf->size = bmz8->m;
+	DEBUGP("Successfully generated minimal perfect hash\n");
+	if (mph->verbosity)
+	{
+		fprintf(stderr, "Successfully generated minimal perfect hash function\n");
+	}
+	return mphf;
+}
+
+static cmph_uint8 bmz8_traverse_critical_nodes(bmz8_config_data_t *bmz8, cmph_uint32 v, cmph_uint8 * biggest_g_value, cmph_uint8 * biggest_edge_value, cmph_uint8 * used_edges, cmph_uint8 * visited)
+{
+        cmph_uint8 next_g;
+	cmph_uint32 u;   /* Auxiliary vertex */
+	cmph_uint32 lav; /* lookahead vertex */
+	cmph_uint8 collision;
+	vqueue_t * q = vqueue_new((cmph_uint32)(graph_ncritical_nodes(bmz8->graph)));
+	graph_iterator_t it, it1;
+
+	DEBUGP("Labelling critical vertices\n");
+	bmz8->g[v] = (cmph_uint8)(ceil ((double)(*biggest_edge_value)/2) - 1);
+	SETBIT(visited, v);
+	next_g    = (cmph_uint8)floor((double)(*biggest_edge_value/2)); /* next_g is incremented in the do..while statement*/
+	vqueue_insert(q, v);
+	while(!vqueue_is_empty(q))
+	{
+		v = vqueue_remove(q);
+		it = graph_neighbors_it(bmz8->graph, v);		
+		while ((u = graph_next_neighbor(bmz8->graph, &it)) != GRAPH_NO_NEIGHBOR)
+		{		        
+               	        if (graph_node_is_critical(bmz8->graph, u) && (!GETBIT(visited,u)))
+			{
+			        collision = 1;
+			        while(collision) // lookahead to resolve collisions
+				{
+ 				        next_g = (cmph_uint8)(*biggest_g_value + 1); 
+					it1 = graph_neighbors_it(bmz8->graph, u);
+					collision = 0;
+					while((lav = graph_next_neighbor(bmz8->graph, &it1)) != GRAPH_NO_NEIGHBOR)
+					{
+  					        if (graph_node_is_critical(bmz8->graph, lav) && GETBIT(visited,lav))
+						{
+   						        if(next_g + bmz8->g[lav] >= bmz8->m)
+							{
+							        vqueue_destroy(q);
+								return 1; // restart mapping step.
+							}
+							if (GETBIT(used_edges, (next_g + bmz8->g[lav]))) 
+							{
+							        collision = 1;
+								break;
+							}
+						}
+					}
+ 					if (next_g > *biggest_g_value) *biggest_g_value = next_g;
+				}		
+				// Marking used edges...
+				it1 = graph_neighbors_it(bmz8->graph, u);
+				while((lav = graph_next_neighbor(bmz8->graph, &it1)) != GRAPH_NO_NEIGHBOR)
+				{
+                 		        if (graph_node_is_critical(bmz8->graph, lav) && GETBIT(visited, lav))
+					{
+                   			        SETBIT(used_edges,(next_g + bmz8->g[lav]));
+
+						if(next_g + bmz8->g[lav] > *biggest_edge_value) 
+                                                    *biggest_edge_value = (cmph_uint8)(next_g + bmz8->g[lav]);
+					}
+				}
+				bmz8->g[u] = next_g; // Labelling vertex u.
+				SETBIT(visited,u);
+			        vqueue_insert(q, u);
+			}			
+	        }
+		 
+	}
+	vqueue_destroy(q);
+	return 0;
+}
+
+static cmph_uint8 bmz8_traverse_critical_nodes_heuristic(bmz8_config_data_t *bmz8, cmph_uint32 v, cmph_uint8 * biggest_g_value, cmph_uint8 * biggest_edge_value, cmph_uint8 * used_edges, cmph_uint8 * visited)
+{
+        cmph_uint8 next_g;
+	cmph_uint32 u;   
+	cmph_uint32 lav; 
+	cmph_uint8 collision;
+	cmph_uint8 * unused_g_values = NULL;
+	cmph_uint8 unused_g_values_capacity = 0;
+	cmph_uint8 nunused_g_values = 0;
+	vqueue_t * q = vqueue_new((cmph_uint32)(graph_ncritical_nodes(bmz8->graph)));
+	graph_iterator_t it, it1;
+
+	DEBUGP("Labelling critical vertices\n");
+	bmz8->g[v] = (cmph_uint8)(ceil ((double)(*biggest_edge_value)/2) - 1);
+	SETBIT(visited, v);
+	next_g    = (cmph_uint8)floor((double)(*biggest_edge_value/2)); 
+	vqueue_insert(q, v);
+	while(!vqueue_is_empty(q))
+	{
+		v = vqueue_remove(q);
+		it = graph_neighbors_it(bmz8->graph, v);		
+		while ((u = graph_next_neighbor(bmz8->graph, &it)) != GRAPH_NO_NEIGHBOR)
+		{		        
+               	        if (graph_node_is_critical(bmz8->graph, u) && (!GETBIT(visited,u)))
+			{
+			        cmph_uint8 next_g_index = 0;
+			        collision = 1;
+			        while(collision) // lookahead to resolve collisions
+				{
+				        if (next_g_index < nunused_g_values) 
+					{
+					        next_g = unused_g_values[next_g_index++];
+					}
+					else    
+					{
+					        next_g = (cmph_uint8)(*biggest_g_value + 1); 
+						next_g_index = 255;//UINT_MAX;
+					}
+					it1 = graph_neighbors_it(bmz8->graph, u);
+					collision = 0;
+					while((lav = graph_next_neighbor(bmz8->graph, &it1)) != GRAPH_NO_NEIGHBOR)
+					{
+  					        if (graph_node_is_critical(bmz8->graph, lav) && GETBIT(visited,lav))
+						{
+   						        if(next_g + bmz8->g[lav] >= bmz8->m)
+							{
+							        vqueue_destroy(q);
+								free(unused_g_values);
+								return 1; // restart mapping step.
+							}
+							if (GETBIT(used_edges, (next_g + bmz8->g[lav]))) 
+							{
+							        collision = 1;
+								break;
+							}
+						}
+					}
+					if(collision && (next_g > *biggest_g_value)) // saving the current g value stored in next_g.
+					{
+					        if(nunused_g_values == unused_g_values_capacity)
+						{
+							unused_g_values = (cmph_uint8*)realloc(unused_g_values, ((size_t)(unused_g_values_capacity + BUFSIZ))*sizeof(cmph_uint8));
+						        unused_g_values_capacity += (cmph_uint8)BUFSIZ;  							
+						} 
+						unused_g_values[nunused_g_values++] = next_g;							
+
+					}
+ 					if (next_g > *biggest_g_value) *biggest_g_value = next_g;
+				}
+				
+				next_g_index--;
+				if (next_g_index < nunused_g_values) unused_g_values[next_g_index] = unused_g_values[--nunused_g_values];
+
+				// Marking used edges...
+				it1 = graph_neighbors_it(bmz8->graph, u);
+				while((lav = graph_next_neighbor(bmz8->graph, &it1)) != GRAPH_NO_NEIGHBOR)
+				{
+                 		        if (graph_node_is_critical(bmz8->graph, lav) && GETBIT(visited, lav))
+					{
+                   			        SETBIT(used_edges,(next_g + bmz8->g[lav]));
+						if(next_g + bmz8->g[lav] > *biggest_edge_value) 
+                                                    *biggest_edge_value = (cmph_uint8)(next_g + bmz8->g[lav]);
+					}
+				}
+				
+				bmz8->g[u] = next_g; // Labelling vertex u.
+				SETBIT(visited, u);
+			      	vqueue_insert(q, u);
+				
+			}			
+	        }
+		 
+	}
+	vqueue_destroy(q);
+	free(unused_g_values);
+	return 0;  
+}
+
+static cmph_uint8 next_unused_edge(bmz8_config_data_t *bmz8, cmph_uint8 * used_edges, cmph_uint32 unused_edge_index)
+{
+       while(1)
+       {
+		assert(unused_edge_index < bmz8->m);
+		if(GETBIT(used_edges, unused_edge_index)) unused_edge_index ++;
+		else break;
+       }
+       return (cmph_uint8)unused_edge_index;
+}
+
+static void bmz8_traverse(bmz8_config_data_t *bmz8, cmph_uint8 * used_edges, cmph_uint32 v, cmph_uint8 * unused_edge_index, cmph_uint8 * visited)
+{
+	graph_iterator_t it = graph_neighbors_it(bmz8->graph, v);
+	cmph_uint32 neighbor = 0;
+	while((neighbor = graph_next_neighbor(bmz8->graph, &it)) != GRAPH_NO_NEIGHBOR)
+	{
+     	        if(GETBIT(visited,neighbor)) continue;
+		//DEBUGP("Visiting neighbor %u\n", neighbor);
+		*unused_edge_index = next_unused_edge(bmz8, used_edges, *unused_edge_index);
+		bmz8->g[neighbor] = (cmph_uint8)(*unused_edge_index - bmz8->g[v]);
+		//if (bmz8->g[neighbor] >= bmz8->m) bmz8->g[neighbor] += bmz8->m;
+		SETBIT(visited, neighbor);
+		(*unused_edge_index)++;
+		bmz8_traverse(bmz8, used_edges, neighbor, unused_edge_index, visited);
+		
+	}  
+}
+
+static void bmz8_traverse_non_critical_nodes(bmz8_config_data_t *bmz8, cmph_uint8 * used_edges, cmph_uint8 * visited)
+{
+
+	cmph_uint8 i, v1, v2, unused_edge_index = 0;
+	DEBUGP("Labelling non critical vertices\n");
+	for(i = 0; i < bmz8->m; i++)
+	{
+	        v1 = (cmph_uint8)graph_vertex_id(bmz8->graph, i, 0);
+		v2 = (cmph_uint8)graph_vertex_id(bmz8->graph, i, 1);
+		if((GETBIT(visited,v1) && GETBIT(visited,v2)) || (!GETBIT(visited,v1) && !GETBIT(visited,v2))) continue;				  	
+		if(GETBIT(visited,v1)) bmz8_traverse(bmz8, used_edges, v1, &unused_edge_index, visited);
+	        else bmz8_traverse(bmz8, used_edges, v2, &unused_edge_index, visited);
+
+	}
+
+	for(i = 0; i < bmz8->n; i++)
+	{
+		if(!GETBIT(visited,i))
+		{ 	                        
+		        bmz8->g[i] = 0;
+			SETBIT(visited, i);
+			bmz8_traverse(bmz8, used_edges, i, &unused_edge_index, visited);
+		}
+	}
+
+}
+		
+static int bmz8_gen_edges(cmph_config_t *mph)
+{
+	cmph_uint8 e;
+	bmz8_config_data_t *bmz8 = (bmz8_config_data_t *)mph->data;
+	cmph_uint8 multiple_edges = 0;
+	DEBUGP("Generating edges for %u vertices\n", bmz8->n);
+	graph_clear_edges(bmz8->graph);	
+	mph->key_source->rewind(mph->key_source->data);
+	for (e = 0; e < mph->key_source->nkeys; ++e)
+	{
+		cmph_uint8 h1, h2;
+		cmph_uint32 keylen;
+		char *key = NULL;
+		mph->key_source->read(mph->key_source->data, &key, &keylen);
+		
+//		if (key == NULL)fprintf(stderr, "key = %s -- read BMZ\n", key);
+		h1 = (cmph_uint8)(hash(bmz8->hashes[0], key, keylen) % bmz8->n);
+		h2 = (cmph_uint8)(hash(bmz8->hashes[1], key, keylen) % bmz8->n);
+		if (h1 == h2) if (++h2 >= bmz8->n) h2 = 0;
+		if (h1 == h2) 
+		{
+			if (mph->verbosity) fprintf(stderr, "Self loop for key %u\n", e);
+			mph->key_source->dispose(mph->key_source->data, key, keylen);
+			return 0;
+		}
+		//DEBUGP("Adding edge: %u -> %u for key %s\n", h1, h2, key);
+		mph->key_source->dispose(mph->key_source->data, key, keylen);
+//		fprintf(stderr, "key = %s -- dispose BMZ\n", key);
+		multiple_edges = graph_contains_edge(bmz8->graph, h1, h2);
+		if (mph->verbosity && multiple_edges) fprintf(stderr, "A non simple graph was generated\n");
+		if (multiple_edges) return 0; // checking multiple edge restriction.
+		graph_add_edge(bmz8->graph, h1, h2);
+	}
+	return !multiple_edges;
+}
+
+int bmz8_dump(cmph_t *mphf, FILE *fd)
+{
+	char *buf = NULL;
+	cmph_uint32 buflen;
+	cmph_uint8 two = 2; //number of hash functions
+	bmz8_data_t *data = (bmz8_data_t *)mphf->data;
+	register size_t nbytes;
+	__cmph_dump(mphf, fd);
+
+	nbytes = fwrite(&two, sizeof(cmph_uint8), (size_t)1, fd);
+
+	hash_state_dump(data->hashes[0], &buf, &buflen);
+	DEBUGP("Dumping hash state with %u bytes to disk\n", buflen);
+	nbytes = fwrite(&buflen, sizeof(cmph_uint32), (size_t)1, fd);
+	nbytes = fwrite(buf, (size_t)buflen, (size_t)1, fd);
+	free(buf);
+
+	hash_state_dump(data->hashes[1], &buf, &buflen);
+	DEBUGP("Dumping hash state with %u bytes to disk\n", buflen);
+	nbytes = fwrite(&buflen, sizeof(cmph_uint32), (size_t)1, fd);
+	nbytes = fwrite(buf, (size_t)buflen, (size_t)1, fd);
+	free(buf);
+
+	nbytes = fwrite(&(data->n), sizeof(cmph_uint8), (size_t)1, fd);
+	nbytes = fwrite(&(data->m), sizeof(cmph_uint8), (size_t)1, fd);
+	
+	nbytes = fwrite(data->g, sizeof(cmph_uint8)*(data->n), (size_t)1, fd);
+/*	#ifdef DEBUG
+	fprintf(stderr, "G: ");
+	for (i = 0; i < data->n; ++i) fprintf(stderr, "%u ", data->g[i]);
+	fprintf(stderr, "\n");
+	#endif*/
+	return 1;
+}
+
+void bmz8_load(FILE *f, cmph_t *mphf)
+{
+	cmph_uint8 nhashes;
+	char *buf = NULL;
+	cmph_uint32 buflen;
+	cmph_uint8 i;
+	register size_t nbytes;
+	bmz8_data_t *bmz8 = (bmz8_data_t *)malloc(sizeof(bmz8_data_t));
+
+	DEBUGP("Loading bmz8 mphf\n");
+	mphf->data = bmz8;
+	nbytes = fread(&nhashes, sizeof(cmph_uint8), (size_t)1, f);
+	bmz8->hashes = (hash_state_t **)malloc(sizeof(hash_state_t *)*(size_t)(nhashes + 1));
+	bmz8->hashes[nhashes] = NULL;
+	DEBUGP("Reading %u hashes\n", nhashes);
+	for (i = 0; i < nhashes; ++i)
+	{
+		hash_state_t *state = NULL;
+		nbytes = fread(&buflen, sizeof(cmph_uint32), (size_t)1, f);
+		DEBUGP("Hash state has %u bytes\n", buflen);
+		buf = (char *)malloc((size_t)buflen);
+		nbytes = fread(buf, (size_t)buflen, (size_t)1, f);
+		state = hash_state_load(buf, buflen);
+		bmz8->hashes[i] = state;
+		free(buf);
+	}
+
+	DEBUGP("Reading m and n\n");
+	nbytes = fread(&(bmz8->n), sizeof(cmph_uint8), (size_t)1, f);	
+	nbytes = fread(&(bmz8->m), sizeof(cmph_uint8), (size_t)1, f);	
+
+	bmz8->g = (cmph_uint8 *)malloc(sizeof(cmph_uint8)*bmz8->n);
+	nbytes = fread(bmz8->g, bmz8->n*sizeof(cmph_uint8), (size_t)1, f);
+	#ifdef DEBUG
+	fprintf(stderr, "G: ");
+	for (i = 0; i < bmz8->n; ++i) fprintf(stderr, "%u ", bmz8->g[i]);
+	fprintf(stderr, "\n");
+	#endif
+	return;
+}
+		
+
+cmph_uint8 bmz8_search(cmph_t *mphf, const char *key, cmph_uint32 keylen)
+{
+	bmz8_data_t *bmz8 = mphf->data;
+	cmph_uint8 h1 = (cmph_uint8)(hash(bmz8->hashes[0], key, keylen) % bmz8->n);
+	cmph_uint8 h2 = (cmph_uint8)(hash(bmz8->hashes[1], key, keylen) % bmz8->n);
+	DEBUGP("key: %s h1: %u h2: %u\n", key, h1, h2);
+	if (h1 == h2 && ++h2 > bmz8->n) h2 = 0;
+	DEBUGP("key: %s g[h1]: %u g[h2]: %u edges: %u\n", key, bmz8->g[h1], bmz8->g[h2], bmz8->m);
+	return (cmph_uint8)(bmz8->g[h1] + bmz8->g[h2]);
+}
+void bmz8_destroy(cmph_t *mphf)
+{
+	bmz8_data_t *data = (bmz8_data_t *)mphf->data;
+	free(data->g);
+	hash_state_destroy(data->hashes[0]);
+	hash_state_destroy(data->hashes[1]);
+	free(data->hashes);
+	free(data);
+	free(mphf);
+}
+
+/** \fn void bmz8_pack(cmph_t *mphf, void *packed_mphf);
+ *  \brief Support the ability to pack a perfect hash function into a preallocated contiguous memory space pointed by packed_mphf.
+ *  \param mphf pointer to the resulting mphf
+ *  \param packed_mphf pointer to the contiguous memory area used to store the resulting mphf. The size of packed_mphf must be at least cmph_packed_size() 
+ */
+void bmz8_pack(cmph_t *mphf, void *packed_mphf)
+{
+	bmz8_data_t *data = (bmz8_data_t *)mphf->data;
+	cmph_uint8 * ptr = packed_mphf;
+
+	// packing h1 type
+	CMPH_HASH h1_type = hash_get_type(data->hashes[0]);
+	*((cmph_uint32 *) ptr) = h1_type;
+	ptr += sizeof(cmph_uint32);
+
+	// packing h1
+	hash_state_pack(data->hashes[0], ptr);
+	ptr += hash_state_packed_size(h1_type);
+
+	// packing h2 type
+	CMPH_HASH h2_type = hash_get_type(data->hashes[1]);
+	*((cmph_uint32 *) ptr) = h2_type;
+	ptr += sizeof(cmph_uint32);
+
+	// packing h2
+	hash_state_pack(data->hashes[1], ptr);
+	ptr += hash_state_packed_size(h2_type);
+
+	// packing n
+	*ptr++ = data->n;
+
+	// packing g
+	memcpy(ptr, data->g, sizeof(cmph_uint8)*data->n);	
+}
+
+/** \fn cmph_uint32 bmz8_packed_size(cmph_t *mphf);
+ *  \brief Return the amount of space needed to pack mphf.
+ *  \param mphf pointer to a mphf
+ *  \return the size of the packed function or zero for failures
+ */ 
+cmph_uint32 bmz8_packed_size(cmph_t *mphf)
+{
+	bmz8_data_t *data = (bmz8_data_t *)mphf->data;
+	CMPH_HASH h1_type = hash_get_type(data->hashes[0]); 
+	CMPH_HASH h2_type = hash_get_type(data->hashes[1]); 
+
+	return (cmph_uint32)(sizeof(CMPH_ALGO) + hash_state_packed_size(h1_type) + hash_state_packed_size(h2_type) + 
+			2*sizeof(cmph_uint32) + sizeof(cmph_uint8) + sizeof(cmph_uint8)*data->n);
+}
+
+/** cmph_uint8 bmz8_search(void *packed_mphf, const char *key, cmph_uint32 keylen);
+ *  \brief Use the packed mphf to do a search. 
+ *  \param  packed_mphf pointer to the packed mphf
+ *  \param key key to be hashed
+ *  \param keylen key legth in bytes
+ *  \return The mphf value
+ */
+cmph_uint8 bmz8_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen)
+{
+	register cmph_uint8 *h1_ptr = packed_mphf;
+	register CMPH_HASH h1_type  = *((cmph_uint32 *)h1_ptr);
+	h1_ptr += 4;
+
+	register cmph_uint8 *h2_ptr = h1_ptr + hash_state_packed_size(h1_type);
+	register CMPH_HASH h2_type  = *((cmph_uint32 *)h2_ptr);
+	h2_ptr += 4;
+	
+	register cmph_uint8 *g_ptr = h2_ptr + hash_state_packed_size(h2_type);
+	
+	register cmph_uint8 n = *g_ptr++;  
+	
+	register cmph_uint8 h1 = (cmph_uint8)(hash_packed(h1_ptr, h1_type, key, keylen) % n); 
+	register cmph_uint8 h2 = (cmph_uint8)(hash_packed(h2_ptr, h2_type, key, keylen) % n); 
+	DEBUGP("key: %s h1: %u h2: %u\n", key, h1, h2);
+	if (h1 == h2 && ++h2 > n) h2 = 0;
+	return (cmph_uint8)(g_ptr[h1] + g_ptr[h2]);	
+}
diff --git a/girepository/cmph/bmz8.h b/girepository/cmph/bmz8.h
new file mode 100644
index 0000000..5456759
--- /dev/null
+++ b/girepository/cmph/bmz8.h
@@ -0,0 +1,42 @@
+#ifndef __CMPH_BMZ8_H__
+#define __CMPH_BMZ8_H__
+
+#include "cmph.h"
+
+typedef struct __bmz8_data_t bmz8_data_t;
+typedef struct __bmz8_config_data_t bmz8_config_data_t;
+
+bmz8_config_data_t *bmz8_config_new();
+void bmz8_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs);
+void bmz8_config_destroy(cmph_config_t *mph);
+cmph_t *bmz8_new(cmph_config_t *mph, double c);
+
+void bmz8_load(FILE *f, cmph_t *mphf);
+int bmz8_dump(cmph_t *mphf, FILE *f);
+void bmz8_destroy(cmph_t *mphf);
+cmph_uint8 bmz8_search(cmph_t *mphf, const char *key, cmph_uint32 keylen);
+
+/** \fn void bmz8_pack(cmph_t *mphf, void *packed_mphf);
+ *  \brief Support the ability to pack a perfect hash function into a preallocated contiguous memory space pointed by packed_mphf.
+ *  \param mphf pointer to the resulting mphf
+ *  \param packed_mphf pointer to the contiguous memory area used to store the resulting mphf. The size of packed_mphf must be at least cmph_packed_size() 
+ */
+void bmz8_pack(cmph_t *mphf, void *packed_mphf);
+
+/** \fn cmph_uint32 bmz8_packed_size(cmph_t *mphf);
+ *  \brief Return the amount of space needed to pack mphf.
+ *  \param mphf pointer to a mphf
+ *  \return the size of the packed function or zero for failures
+ */ 
+cmph_uint32 bmz8_packed_size(cmph_t *mphf);
+
+/** cmph_uint8 bmz8_search(void *packed_mphf, const char *key, cmph_uint32 keylen);
+ *  \brief Use the packed mphf to do a search. 
+ *  \param  packed_mphf pointer to the packed mphf
+ *  \param key key to be hashed
+ *  \param keylen key legth in bytes
+ *  \return The mphf value
+ */
+cmph_uint8 bmz8_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen);
+
+#endif
diff --git a/girepository/cmph/bmz8_structs.h b/girepository/cmph/bmz8_structs.h
new file mode 100644
index 0000000..408b529
--- /dev/null
+++ b/girepository/cmph/bmz8_structs.h
@@ -0,0 +1,25 @@
+#ifndef __CMPH_BMZ8_STRUCTS_H__
+#define __CMPH_BMZ8_STRUCTS_H__
+
+#include "hash_state.h"
+
+struct __bmz8_data_t
+{
+	cmph_uint8 m; //edges (words) count
+	cmph_uint8 n; //vertex count
+	cmph_uint8 *g;
+	hash_state_t **hashes;
+};
+
+
+struct __bmz8_config_data_t
+{
+	CMPH_HASH hashfuncs[2];
+	cmph_uint8 m; //edges (words) count
+	cmph_uint8 n; //vertex count
+	graph_t *graph;
+	cmph_uint8 *g;
+	hash_state_t **hashes;
+};
+
+#endif
diff --git a/girepository/cmph/bmz_structs.h b/girepository/cmph/bmz_structs.h
new file mode 100644
index 0000000..67065a0
--- /dev/null
+++ b/girepository/cmph/bmz_structs.h
@@ -0,0 +1,25 @@
+#ifndef __CMPH_BMZ_STRUCTS_H__
+#define __CMPH_BMZ_STRUCTS_H__
+
+#include "hash_state.h"
+
+struct __bmz_data_t
+{
+	cmph_uint32 m; //edges (words) count
+	cmph_uint32 n; //vertex count
+	cmph_uint32 *g;
+	hash_state_t **hashes;
+};
+
+
+struct __bmz_config_data_t
+{
+	CMPH_HASH hashfuncs[2];
+	cmph_uint32 m; //edges (words) count
+	cmph_uint32 n; //vertex count
+	graph_t *graph;
+	cmph_uint32 *g;
+	hash_state_t **hashes;
+};
+
+#endif
diff --git a/girepository/cmph/brz.c b/girepository/cmph/brz.c
new file mode 100755
index 0000000..eb89ac0
--- /dev/null
+++ b/girepository/cmph/brz.c
@@ -0,0 +1,985 @@
+#include "graph.h"
+#include "fch.h"
+#include "fch_structs.h"
+#include "bmz8.h"
+#include "bmz8_structs.h"
+#include "brz.h"
+#include "cmph_structs.h"
+#include "brz_structs.h"
+#include "buffer_manager.h"
+#include "cmph.h"
+#include "hash.h"
+#include "bitbool.h"
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#define MAX_BUCKET_SIZE 255
+//#define DEBUG
+#include "debug.h"
+
+static int brz_gen_mphf(cmph_config_t *mph);
+static cmph_uint32 brz_min_index(cmph_uint32 * vector, cmph_uint32 n);
+static void brz_destroy_keys_vd(cmph_uint8 ** keys_vd, cmph_uint32 nkeys);
+static char * brz_copy_partial_fch_mphf(brz_config_data_t *brz, fch_data_t * fchf, cmph_uint32 index,  cmph_uint32 *buflen);
+static char * brz_copy_partial_bmz8_mphf(brz_config_data_t *brz, bmz8_data_t * bmzf, cmph_uint32 index,  cmph_uint32 *buflen);
+brz_config_data_t *brz_config_new()
+{
+	brz_config_data_t *brz = NULL; 	
+	brz = (brz_config_data_t *)malloc(sizeof(brz_config_data_t));
+	brz->algo = CMPH_FCH;
+	brz->b = 128;
+	brz->hashfuncs[0] = CMPH_HASH_JENKINS;
+	brz->hashfuncs[1] = CMPH_HASH_JENKINS;
+	brz->hashfuncs[2] = CMPH_HASH_JENKINS;
+	brz->size   = NULL;
+	brz->offset = NULL;
+	brz->g      = NULL;
+	brz->h1 = NULL;
+	brz->h2 = NULL;
+	brz->h0 = NULL;
+	brz->memory_availability = 1024*1024;
+	brz->tmp_dir = (cmph_uint8 *)calloc((size_t)10, sizeof(cmph_uint8));
+	brz->mphf_fd = NULL;
+	strcpy((char *)(brz->tmp_dir), "/var/tmp/"); 
+	assert(brz);
+	return brz;
+}
+
+void brz_config_destroy(cmph_config_t *mph)
+{
+	brz_config_data_t *data = (brz_config_data_t *)mph->data;
+	free(data->tmp_dir);
+	DEBUGP("Destroying algorithm dependent data\n");
+	free(data);
+}
+
+void brz_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs)
+{
+	brz_config_data_t *brz = (brz_config_data_t *)mph->data;
+	CMPH_HASH *hashptr = hashfuncs;
+	cmph_uint32 i = 0;
+	while(*hashptr != CMPH_HASH_COUNT)
+	{
+		if (i >= 3) break; //brz only uses three hash functions
+		brz->hashfuncs[i] = *hashptr;	
+		++i, ++hashptr;
+	}
+}
+
+void brz_config_set_memory_availability(cmph_config_t *mph, cmph_uint32 memory_availability)
+{
+	brz_config_data_t *brz = (brz_config_data_t *)mph->data;
+	if(memory_availability > 0) brz->memory_availability = memory_availability*1024*1024;
+}
+
+void brz_config_set_tmp_dir(cmph_config_t *mph, cmph_uint8 *tmp_dir)
+{
+	brz_config_data_t *brz = (brz_config_data_t *)mph->data;
+	if(tmp_dir)
+	{
+		size_t len = strlen((char *)tmp_dir);
+		free(brz->tmp_dir);
+		if(tmp_dir[len-1] != '/')
+		{
+			brz->tmp_dir = (cmph_uint8 *)calloc((size_t)len+2, sizeof(cmph_uint8));
+			sprintf((char *)(brz->tmp_dir), "%s/", (char *)tmp_dir); 
+		}
+		else
+		{
+			brz->tmp_dir = (cmph_uint8 *)calloc((size_t)len+1, sizeof(cmph_uint8));
+			sprintf((char *)(brz->tmp_dir), "%s", (char *)tmp_dir); 
+		}
+		
+	}
+}
+
+void brz_config_set_mphf_fd(cmph_config_t *mph, FILE *mphf_fd)
+{
+	brz_config_data_t *brz = (brz_config_data_t *)mph->data;
+	brz->mphf_fd = mphf_fd;
+	assert(brz->mphf_fd);
+}
+
+void brz_config_set_b(cmph_config_t *mph, cmph_uint32 b)
+{
+	brz_config_data_t *brz = (brz_config_data_t *)mph->data;
+	if(b <= 64 || b >= 175) 
+	{
+		b =  128;
+	}
+	brz->b = (cmph_uint8)b;
+}
+
+void brz_config_set_algo(cmph_config_t *mph, CMPH_ALGO algo) 
+{
+	if (algo == CMPH_BMZ8 || algo == CMPH_FCH) // supported algorithms
+	{
+		brz_config_data_t *brz = (brz_config_data_t *)mph->data;
+		brz->algo = algo;
+	}
+}
+
+cmph_t *brz_new(cmph_config_t *mph, double c)
+{
+	cmph_t *mphf = NULL;
+	brz_data_t *brzf = NULL;
+	cmph_uint32 i;
+	cmph_uint32 iterations = 20;
+
+	DEBUGP("c: %f\n", c);
+	brz_config_data_t *brz = (brz_config_data_t *)mph->data;
+	switch(brz->algo) // validating restrictions over parameter c.
+	{
+		case CMPH_BMZ8:
+			if (c == 0 || c >= 2.0) c = 1;
+			break;
+		case CMPH_FCH:
+			if (c <= 2.0) c = 2.6;
+			break;
+		default:
+			assert(0);
+	}
+	brz->c = c;
+	brz->m = mph->key_source->nkeys;
+	DEBUGP("m: %u\n", brz->m);
+        brz->k = (cmph_uint32)ceil(brz->m/((double)brz->b));
+	DEBUGP("k: %u\n", brz->k);
+	brz->size   = (cmph_uint8 *) calloc((size_t)brz->k, sizeof(cmph_uint8));
+	
+	// Clustering the keys by graph id.
+	if (mph->verbosity)
+	{
+		fprintf(stderr, "Partioning the set of keys.\n");	
+	}
+		
+	while(1)
+	{
+		int ok;
+		DEBUGP("hash function 3\n");
+		brz->h0 = hash_state_new(brz->hashfuncs[2], brz->k);
+		DEBUGP("Generating graphs\n");
+		ok = brz_gen_mphf(mph);
+		if (!ok)
+		{
+			--iterations;
+			hash_state_destroy(brz->h0);
+			brz->h0 = NULL;
+			DEBUGP("%u iterations remaining to create the graphs in a external file\n", iterations);
+			if (mph->verbosity)
+			{
+				fprintf(stderr, "Failure: A graph with more than 255 keys was created - %u iterations remaining\n", iterations);
+			}
+			if (iterations == 0) break;
+		} 
+		else break;	
+	}
+	if (iterations == 0) 
+	{
+		DEBUGP("Graphs with more than 255 keys were created in all 20 iterations\n");
+		free(brz->size);
+		return NULL;
+	}
+	DEBUGP("Graphs generated\n");
+	
+	brz->offset = (cmph_uint32 *)calloc((size_t)brz->k, sizeof(cmph_uint32));
+	for (i = 1; i < brz->k; ++i)
+	{
+		brz->offset[i] = brz->size[i-1] + brz->offset[i-1];
+	}
+	// Generating a mphf
+	mphf = (cmph_t *)malloc(sizeof(cmph_t));
+	mphf->algo = mph->algo;
+	brzf = (brz_data_t *)malloc(sizeof(brz_data_t));
+	brzf->g = brz->g;
+	brz->g = NULL; //transfer memory ownership
+	brzf->h1 = brz->h1;
+	brz->h1 = NULL; //transfer memory ownership
+	brzf->h2 = brz->h2;
+	brz->h2 = NULL; //transfer memory ownership
+	brzf->h0 = brz->h0;
+	brz->h0 = NULL; //transfer memory ownership
+	brzf->size = brz->size;
+	brz->size = NULL; //transfer memory ownership
+	brzf->offset = brz->offset;
+	brz->offset = NULL; //transfer memory ownership
+	brzf->k = brz->k;
+	brzf->c = brz->c;
+	brzf->m = brz->m;
+	brzf->algo = brz->algo;
+	mphf->data = brzf;
+	mphf->size = brz->m;	
+	DEBUGP("Successfully generated minimal perfect hash\n");
+	if (mph->verbosity)
+	{
+		fprintf(stderr, "Successfully generated minimal perfect hash function\n");
+	}
+	return mphf;
+}
+
+static int brz_gen_mphf(cmph_config_t *mph)
+{
+	cmph_uint32 i, e, error;
+	brz_config_data_t *brz = (brz_config_data_t *)mph->data;
+	cmph_uint32 memory_usage = 0;
+	cmph_uint32 nkeys_in_buffer = 0;
+	cmph_uint8 *buffer = (cmph_uint8 *)malloc((size_t)brz->memory_availability);
+	cmph_uint32 *buckets_size = (cmph_uint32 *)calloc((size_t)brz->k, sizeof(cmph_uint32));
+	cmph_uint32 *keys_index = NULL;
+	cmph_uint8 **buffer_merge = NULL;
+	cmph_uint32 *buffer_h0 = NULL;
+	cmph_uint32 nflushes = 0;
+	cmph_uint32 h0;
+	register size_t nbytes;
+	FILE *  tmp_fd = NULL;
+	buffer_manager_t * buff_manager = NULL;
+	char *filename = NULL;
+	char *key = NULL;
+	cmph_uint32 keylen;
+	cmph_uint32 cur_bucket = 0;
+	cmph_uint8 nkeys_vd = 0;
+	cmph_uint8 ** keys_vd = NULL;
+	
+	mph->key_source->rewind(mph->key_source->data);
+	DEBUGP("Generating graphs from %u keys\n", brz->m);
+	// Partitioning
+	for (e = 0; e < brz->m; ++e)
+	{
+		mph->key_source->read(mph->key_source->data, &key, &keylen);
+
+		/* Buffers management */
+		if (memory_usage + keylen + sizeof(keylen) > brz->memory_availability) // flush buffers 
+		{
+			if(mph->verbosity)
+			{
+				fprintf(stderr, "Flushing  %u\n", nkeys_in_buffer);
+			}
+			cmph_uint32 value = buckets_size[0];
+			cmph_uint32 sum = 0;
+			cmph_uint32 keylen1 = 0;
+			buckets_size[0]   = 0;
+			for(i = 1; i < brz->k; i++)
+			{
+				if(buckets_size[i] == 0) continue;
+				sum += value;
+				value = buckets_size[i];
+				buckets_size[i] = sum;
+				
+			}	
+			memory_usage = 0;
+			keys_index = (cmph_uint32 *)calloc((size_t)nkeys_in_buffer, sizeof(cmph_uint32));
+			for(i = 0; i < nkeys_in_buffer; i++)
+			{
+				memcpy(&keylen1, buffer + memory_usage, sizeof(keylen1));
+				h0 = hash(brz->h0, (char *)(buffer + memory_usage + sizeof(keylen1)), keylen1) % brz->k;
+				keys_index[buckets_size[h0]] = memory_usage;
+				buckets_size[h0]++;
+				memory_usage +=  keylen1 + (cmph_uint32)sizeof(keylen1);
+			}
+			filename = (char *)calloc(strlen((char *)(brz->tmp_dir)) + 11, sizeof(char));
+			sprintf(filename, "%s%u.cmph",brz->tmp_dir, nflushes);
+			tmp_fd = fopen(filename, "wb");
+			free(filename);
+			filename = NULL;
+			for(i = 0; i < nkeys_in_buffer; i++)
+			{
+				memcpy(&keylen1, buffer + keys_index[i], sizeof(keylen1));
+				nbytes = fwrite(buffer + keys_index[i], (size_t)1, keylen1 + sizeof(keylen1), tmp_fd);
+			}
+			nkeys_in_buffer = 0;
+			memory_usage = 0;
+			memset((void *)buckets_size, 0, brz->k*sizeof(cmph_uint32));
+			nflushes++;
+			free(keys_index);
+			fclose(tmp_fd);
+		}
+		memcpy(buffer + memory_usage, &keylen, sizeof(keylen));
+		memcpy(buffer + memory_usage + sizeof(keylen), key, (size_t)keylen);
+		memory_usage += keylen + (cmph_uint32)sizeof(keylen);
+		h0 = hash(brz->h0, key, keylen) % brz->k;
+		
+		if ((brz->size[h0] == MAX_BUCKET_SIZE) || (brz->algo == CMPH_BMZ8 && ((brz->c >= 1.0) && (cmph_uint8)(brz->c * brz->size[h0]) < brz->size[h0]))) 
+		{
+			free(buffer);
+			free(buckets_size);
+			return 0;
+		}
+		brz->size[h0] = (cmph_uint8)(brz->size[h0] + 1U);
+		buckets_size[h0] ++;
+		nkeys_in_buffer++;
+		mph->key_source->dispose(mph->key_source->data, key, keylen);
+	}
+	if (memory_usage != 0) // flush buffers 
+	{ 
+		if(mph->verbosity)
+		{
+			fprintf(stderr, "Flushing  %u\n", nkeys_in_buffer);
+		}
+		cmph_uint32 value = buckets_size[0];
+		cmph_uint32 sum = 0;
+		cmph_uint32 keylen1 = 0;
+		buckets_size[0]   = 0;
+		for(i = 1; i < brz->k; i++)
+		{
+			if(buckets_size[i] == 0) continue;
+			sum += value;
+			value = buckets_size[i];
+			buckets_size[i] = sum;
+		}
+		memory_usage = 0;
+		keys_index = (cmph_uint32 *)calloc((size_t)nkeys_in_buffer, sizeof(cmph_uint32));
+		for(i = 0; i < nkeys_in_buffer; i++)
+		{
+			memcpy(&keylen1, buffer + memory_usage, sizeof(keylen1));
+			h0 = hash(brz->h0, (char *)(buffer + memory_usage + sizeof(keylen1)), keylen1) % brz->k;
+			keys_index[buckets_size[h0]] = memory_usage;
+			buckets_size[h0]++;
+			memory_usage +=  keylen1 + (cmph_uint32)sizeof(keylen1);
+		}
+		filename = (char *)calloc(strlen((char *)(brz->tmp_dir)) + 11, sizeof(char));
+		sprintf(filename, "%s%u.cmph",brz->tmp_dir, nflushes);
+		tmp_fd = fopen(filename, "wb");
+		free(filename);
+		filename = NULL;
+		for(i = 0; i < nkeys_in_buffer; i++)
+		{
+			memcpy(&keylen1, buffer + keys_index[i], sizeof(keylen1));
+			nbytes = fwrite(buffer + keys_index[i], (size_t)1, keylen1 + sizeof(keylen1), tmp_fd);
+		}
+		nkeys_in_buffer = 0;
+		memory_usage = 0;
+		memset((void *)buckets_size, 0, brz->k*sizeof(cmph_uint32));
+		nflushes++;
+		free(keys_index);
+		fclose(tmp_fd);
+	}
+
+	free(buffer);
+	free(buckets_size);
+	if(nflushes > 1024) return 0; // Too many files generated.
+	// mphf generation
+	if(mph->verbosity)
+	{
+		fprintf(stderr, "\nMPHF generation \n");
+	}
+	/* Starting to dump to disk the resultant MPHF: __cmph_dump function */
+	nbytes = fwrite(cmph_names[CMPH_BRZ], (size_t)(strlen(cmph_names[CMPH_BRZ]) + 1), (size_t)1, brz->mphf_fd);
+	nbytes = fwrite(&(brz->m), sizeof(brz->m), (size_t)1, brz->mphf_fd);
+	nbytes = fwrite(&(brz->c), sizeof(double), (size_t)1, brz->mphf_fd);
+	nbytes = fwrite(&(brz->algo), sizeof(brz->algo), (size_t)1, brz->mphf_fd);
+	nbytes = fwrite(&(brz->k), sizeof(cmph_uint32), (size_t)1, brz->mphf_fd); // number of MPHFs
+	nbytes = fwrite(brz->size, sizeof(cmph_uint8)*(brz->k), (size_t)1, brz->mphf_fd);
+	
+	//tmp_fds = (FILE **)calloc(nflushes, sizeof(FILE *));
+	buff_manager = buffer_manager_new(brz->memory_availability, nflushes);
+	buffer_merge = (cmph_uint8 **)calloc((size_t)nflushes, sizeof(cmph_uint8 *));
+	buffer_h0    = (cmph_uint32 *)calloc((size_t)nflushes, sizeof(cmph_uint32));
+	
+	memory_usage = 0;
+	for(i = 0; i < nflushes; i++)
+	{
+		filename = (char *)calloc(strlen((char *)(brz->tmp_dir)) + 11, sizeof(char));
+		sprintf(filename, "%s%u.cmph",brz->tmp_dir, i);
+		buffer_manager_open(buff_manager, i, filename);
+		free(filename);
+		filename = NULL;
+		key = (char *)buffer_manager_read_key(buff_manager, i, &keylen);
+		h0 = hash(brz->h0, key+sizeof(keylen), keylen) % brz->k;
+		buffer_h0[i] = h0;
+                buffer_merge[i] = (cmph_uint8 *)key;
+                key = NULL; //transfer memory ownership                 
+	}
+	e = 0;
+	keys_vd = (cmph_uint8 **)calloc((size_t)MAX_BUCKET_SIZE, sizeof(cmph_uint8 *));
+	nkeys_vd = 0;
+	error = 0;
+	while(e < brz->m)
+	{
+		i = brz_min_index(buffer_h0, nflushes);
+		cur_bucket = buffer_h0[i];
+		key = (char *)buffer_manager_read_key(buff_manager, i, &keylen);
+		if(key)
+		{
+			while(key)
+			{
+				//keylen = strlen(key);
+				h0 = hash(brz->h0, key+sizeof(keylen), keylen) % brz->k;
+				if (h0 != buffer_h0[i]) break;
+				keys_vd[nkeys_vd++] = (cmph_uint8 *)key;
+				key = NULL; //transfer memory ownership
+				e++;
+				key = (char *)buffer_manager_read_key(buff_manager, i, &keylen);
+			}
+			if (key)
+			{
+				assert(nkeys_vd < brz->size[cur_bucket]);
+				keys_vd[nkeys_vd++] = buffer_merge[i];
+				buffer_merge[i] = NULL; //transfer memory ownership
+				e++;
+				buffer_h0[i] = h0;
+				buffer_merge[i] = (cmph_uint8 *)key;
+			}
+		}
+		if(!key)
+		{
+			assert(nkeys_vd < brz->size[cur_bucket]);
+			keys_vd[nkeys_vd++] = buffer_merge[i];
+			buffer_merge[i] = NULL; //transfer memory ownership
+			e++;
+			buffer_h0[i] = UINT_MAX;
+		}
+		
+		if(nkeys_vd == brz->size[cur_bucket]) // Generating mphf for each bucket.
+		{
+			cmph_io_adapter_t *source = NULL;
+			cmph_config_t *config = NULL;
+			cmph_t *mphf_tmp = NULL;
+			char *bufmphf = NULL;
+			cmph_uint32 buflenmphf = 0;
+			// Source of keys
+			source = cmph_io_byte_vector_adapter(keys_vd, (cmph_uint32)nkeys_vd);
+			config = cmph_config_new(source);
+			cmph_config_set_algo(config, brz->algo);
+			//cmph_config_set_algo(config, CMPH_BMZ8);
+			cmph_config_set_graphsize(config, brz->c);
+			mphf_tmp = cmph_new(config);
+			if (mphf_tmp == NULL) 
+			{
+				if(mph->verbosity) fprintf(stderr, "ERROR: Can't generate MPHF for bucket %u out of %u\n", cur_bucket + 1, brz->k);
+				error = 1;
+				cmph_config_destroy(config);
+ 				brz_destroy_keys_vd(keys_vd, nkeys_vd);
+				cmph_io_byte_vector_adapter_destroy(source);
+				break;
+			}
+			if(mph->verbosity) 
+			{
+			  if (cur_bucket % 1000 == 0) 
+  			  {
+			  	fprintf(stderr, "MPHF for bucket %u out of %u was generated.\n", cur_bucket + 1, brz->k);
+			  }
+			}
+			switch(brz->algo)
+			{
+				case CMPH_FCH:
+				{
+					fch_data_t * fchf = NULL;
+					fchf = (fch_data_t *)mphf_tmp->data;			
+					bufmphf = brz_copy_partial_fch_mphf(brz, fchf, cur_bucket, &buflenmphf);
+				}
+					break;
+				case CMPH_BMZ8:
+				{
+					bmz8_data_t * bmzf = NULL;
+					bmzf = (bmz8_data_t *)mphf_tmp->data;
+					bufmphf = brz_copy_partial_bmz8_mphf(brz, bmzf, cur_bucket,  &buflenmphf);
+				}
+					break;
+				default: assert(0);
+			}
+		        nbytes = fwrite(bufmphf, (size_t)buflenmphf, (size_t)1, brz->mphf_fd);
+			free(bufmphf);
+			bufmphf = NULL;
+			cmph_config_destroy(config);
+ 			brz_destroy_keys_vd(keys_vd, nkeys_vd);
+			cmph_destroy(mphf_tmp);
+			cmph_io_byte_vector_adapter_destroy(source);
+			nkeys_vd = 0;
+		}
+	}
+	buffer_manager_destroy(buff_manager);
+	free(keys_vd);
+	free(buffer_merge);
+	free(buffer_h0);
+	if (error) return 0;
+	return 1;
+}
+
+static cmph_uint32 brz_min_index(cmph_uint32 * vector, cmph_uint32 n)
+{
+	cmph_uint32 i, min_index = 0;
+	for(i = 1; i < n; i++)
+	{
+		if(vector[i] < vector[min_index]) min_index = i;
+	}
+	return min_index;
+}
+
+static void brz_destroy_keys_vd(cmph_uint8 ** keys_vd, cmph_uint32 nkeys)
+{
+	cmph_uint8 i;
+	for(i = 0; i < nkeys; i++) { free(keys_vd[i]); keys_vd[i] = NULL;}
+}
+
+static char * brz_copy_partial_fch_mphf(brz_config_data_t *brz, fch_data_t * fchf, cmph_uint32 index,  cmph_uint32 *buflen)
+{
+	cmph_uint32 i = 0;
+	cmph_uint32 buflenh1 = 0;
+	cmph_uint32 buflenh2 = 0; 
+	char * bufh1 = NULL;
+	char * bufh2 = NULL;
+	char * buf   = NULL;
+	cmph_uint32 n  = fchf->b;//brz->size[index];
+	hash_state_dump(fchf->h1, &bufh1, &buflenh1);
+	hash_state_dump(fchf->h2, &bufh2, &buflenh2);
+	*buflen = buflenh1 + buflenh2 + n + 2U * (cmph_uint32)sizeof(cmph_uint32);
+	buf = (char *)malloc((size_t)(*buflen));
+	memcpy(buf, &buflenh1, sizeof(cmph_uint32));
+	memcpy(buf+sizeof(cmph_uint32), bufh1, (size_t)buflenh1);
+	memcpy(buf+sizeof(cmph_uint32)+buflenh1, &buflenh2, sizeof(cmph_uint32));
+	memcpy(buf+2*sizeof(cmph_uint32)+buflenh1, bufh2, (size_t)buflenh2);	
+	for (i = 0; i < n; i++) memcpy(buf+2*sizeof(cmph_uint32)+buflenh1+buflenh2+i,(fchf->g + i), (size_t)1);
+	free(bufh1);
+	free(bufh2);
+	return buf;
+}
+static char * brz_copy_partial_bmz8_mphf(brz_config_data_t *brz, bmz8_data_t * bmzf, cmph_uint32 index,  cmph_uint32 *buflen)
+{
+	cmph_uint32 buflenh1 = 0;
+	cmph_uint32 buflenh2 = 0; 
+	char * bufh1 = NULL;
+	char * bufh2 = NULL;
+	char * buf   = NULL;
+	cmph_uint32 n = (cmph_uint32)ceil(brz->c * brz->size[index]);
+	hash_state_dump(bmzf->hashes[0], &bufh1, &buflenh1);
+	hash_state_dump(bmzf->hashes[1], &bufh2, &buflenh2);
+	*buflen = buflenh1 + buflenh2 + n + 2U * (cmph_uint32)sizeof(cmph_uint32);
+	buf = (char *)malloc((size_t)(*buflen));
+	memcpy(buf, &buflenh1, sizeof(cmph_uint32));
+	memcpy(buf+sizeof(cmph_uint32), bufh1, (size_t)buflenh1);
+	memcpy(buf+sizeof(cmph_uint32)+buflenh1, &buflenh2, sizeof(cmph_uint32));
+	memcpy(buf+2*sizeof(cmph_uint32)+buflenh1, bufh2, (size_t)buflenh2);
+	memcpy(buf+2*sizeof(cmph_uint32)+buflenh1+buflenh2,bmzf->g, (size_t)n);
+	free(bufh1);
+	free(bufh2);
+	return buf;
+}
+
+
+int brz_dump(cmph_t *mphf, FILE *fd)
+{
+	brz_data_t *data = (brz_data_t *)mphf->data;
+	char *buf = NULL;
+	cmph_uint32 buflen;
+	register size_t nbytes;
+	DEBUGP("Dumping brzf\n");
+	// The initial part of the MPHF have already been dumped to disk during construction
+	// Dumping h0
+        hash_state_dump(data->h0, &buf, &buflen);
+        DEBUGP("Dumping hash state with %u bytes to disk\n", buflen);
+        nbytes = fwrite(&buflen, sizeof(cmph_uint32), (size_t)1, fd);
+        nbytes = fwrite(buf, (size_t)buflen, (size_t)1, fd);
+        free(buf);
+	// Dumping m and the vector offset.
+	nbytes = fwrite(&(data->m), sizeof(cmph_uint32), (size_t)1, fd);	
+	nbytes = fwrite(data->offset, sizeof(cmph_uint32)*(data->k), (size_t)1, fd);
+	return 1;
+}
+
+void brz_load(FILE *f, cmph_t *mphf)
+{
+	char *buf = NULL;
+	cmph_uint32 buflen;
+	register size_t nbytes;
+	cmph_uint32 i, n;
+	brz_data_t *brz = (brz_data_t *)malloc(sizeof(brz_data_t));
+
+	DEBUGP("Loading brz mphf\n");
+	mphf->data = brz;
+	nbytes = fread(&(brz->c), sizeof(double), (size_t)1, f);
+	nbytes = fread(&(brz->algo), sizeof(brz->algo), (size_t)1, f); // Reading algo.
+	nbytes = fread(&(brz->k), sizeof(cmph_uint32), (size_t)1, f);
+	brz->size   = (cmph_uint8 *) malloc(sizeof(cmph_uint8)*brz->k);
+	nbytes = fread(brz->size, sizeof(cmph_uint8)*(brz->k), (size_t)1, f);	
+	brz->h1 = (hash_state_t **)malloc(sizeof(hash_state_t *)*brz->k);
+	brz->h2 = (hash_state_t **)malloc(sizeof(hash_state_t *)*brz->k);
+	brz->g  = (cmph_uint8 **)  calloc((size_t)brz->k, sizeof(cmph_uint8 *));
+	DEBUGP("Reading c = %f   k = %u   algo = %u \n", brz->c, brz->k, brz->algo);
+	//loading h_i1, h_i2 and g_i.
+	for(i = 0; i < brz->k; i++)
+	{
+		// h1
+		nbytes = fread(&buflen, sizeof(cmph_uint32), (size_t)1, f);
+		DEBUGP("Hash state 1 has %u bytes\n", buflen);
+		buf = (char *)malloc((size_t)buflen);
+		nbytes = fread(buf, (size_t)buflen, (size_t)1, f);
+		brz->h1[i] = hash_state_load(buf, buflen);
+		free(buf);
+		//h2
+		nbytes = fread(&buflen, sizeof(cmph_uint32), (size_t)1, f);
+		DEBUGP("Hash state 2 has %u bytes\n", buflen);
+		buf = (char *)malloc((size_t)buflen);
+		nbytes = fread(buf, (size_t)buflen, (size_t)1, f);
+		brz->h2[i] = hash_state_load(buf, buflen);
+		free(buf);
+		switch(brz->algo)
+		{
+			case CMPH_FCH:
+				n = fch_calc_b(brz->c, brz->size[i]);
+				break;
+			case CMPH_BMZ8:
+				n = (cmph_uint32)ceil(brz->c * brz->size[i]);
+				break;
+			default: assert(0);
+		}
+		DEBUGP("g_i has %u bytes\n", n);
+		brz->g[i] = (cmph_uint8 *)calloc((size_t)n, sizeof(cmph_uint8));
+		nbytes = fread(brz->g[i], sizeof(cmph_uint8)*n, (size_t)1, f);
+	}
+	//loading h0
+	nbytes = fread(&buflen, sizeof(cmph_uint32), (size_t)1, f);
+	DEBUGP("Hash state has %u bytes\n", buflen);
+	buf = (char *)malloc((size_t)buflen);
+	nbytes = fread(buf, (size_t)buflen, (size_t)1, f);
+	brz->h0 = hash_state_load(buf, buflen);
+	free(buf);
+
+	//loading c, m, and the vector offset.	
+	nbytes = fread(&(brz->m), sizeof(cmph_uint32), (size_t)1, f);
+	brz->offset = (cmph_uint32 *)malloc(sizeof(cmph_uint32)*brz->k);
+	nbytes = fread(brz->offset, sizeof(cmph_uint32)*(brz->k), (size_t)1, f);
+	return;
+}
+
+static cmph_uint32 brz_bmz8_search(brz_data_t *brz, const char *key, cmph_uint32 keylen, cmph_uint32 * fingerprint)
+{
+	register cmph_uint32 h0;
+
+	hash_vector(brz->h0, key, keylen, fingerprint);
+	h0 = fingerprint[2] % brz->k;
+
+	register cmph_uint32 m = brz->size[h0];
+	register cmph_uint32 n = (cmph_uint32)ceil(brz->c * m);
+	register cmph_uint32 h1 = hash(brz->h1[h0], key, keylen) % n;
+	register cmph_uint32 h2 = hash(brz->h2[h0], key, keylen) % n;
+	register cmph_uint8 mphf_bucket;
+	
+	if (h1 == h2 && ++h2 >= n) h2 = 0;
+	mphf_bucket = (cmph_uint8)(brz->g[h0][h1] + brz->g[h0][h2]); 
+	DEBUGP("key: %s h1: %u h2: %u h0: %u\n", key, h1, h2, h0);
+	DEBUGP("key: %s g[h1]: %u g[h2]: %u offset[h0]: %u edges: %u\n", key, brz->g[h0][h1], brz->g[h0][h2], brz->offset[h0], brz->m);
+	DEBUGP("Address: %u\n", mphf_bucket + brz->offset[h0]);
+	return (mphf_bucket + brz->offset[h0]);
+}
+
+static cmph_uint32 brz_fch_search(brz_data_t *brz, const char *key, cmph_uint32 keylen, cmph_uint32 * fingerprint)
+{
+	register cmph_uint32 h0;
+
+	hash_vector(brz->h0, key, keylen, fingerprint);
+	h0 = fingerprint[2] % brz->k;
+
+	register cmph_uint32 m = brz->size[h0];
+	register cmph_uint32 b = fch_calc_b(brz->c, m);
+	register double p1 = fch_calc_p1(m);
+	register double p2 = fch_calc_p2(b);
+	register cmph_uint32 h1 = hash(brz->h1[h0], key, keylen) % m;
+	register cmph_uint32 h2 = hash(brz->h2[h0], key, keylen) % m;
+	register cmph_uint8 mphf_bucket = 0;
+	h1 = mixh10h11h12(b, p1, p2, h1);
+	mphf_bucket = (cmph_uint8)((h2 + brz->g[h0][h1]) % m);
+	return (mphf_bucket + brz->offset[h0]);
+}
+
+cmph_uint32 brz_search(cmph_t *mphf, const char *key, cmph_uint32 keylen)
+{
+	brz_data_t *brz = mphf->data;
+	cmph_uint32 fingerprint[3];
+	switch(brz->algo)
+	{
+		case CMPH_FCH:
+			return brz_fch_search(brz, key, keylen, fingerprint);
+		case CMPH_BMZ8:
+			return brz_bmz8_search(brz, key, keylen, fingerprint);
+		default: assert(0);
+	}
+	return 0;
+}
+void brz_destroy(cmph_t *mphf)
+{
+	cmph_uint32 i;
+	brz_data_t *data = (brz_data_t *)mphf->data;
+	if(data->g)
+	{
+		for(i = 0; i < data->k; i++)
+		{
+			free(data->g[i]);
+			hash_state_destroy(data->h1[i]);
+			hash_state_destroy(data->h2[i]);
+		}
+		free(data->g);
+		free(data->h1);
+		free(data->h2);
+	}
+	hash_state_destroy(data->h0);
+	free(data->size);
+	free(data->offset);
+	free(data);
+	free(mphf);
+}
+
+/** \fn void brz_pack(cmph_t *mphf, void *packed_mphf);
+ *  \brief Support the ability to pack a perfect hash function into a preallocated contiguous memory space pointed by packed_mphf.
+ *  \param mphf pointer to the resulting mphf
+ *  \param packed_mphf pointer to the contiguous memory area used to store the resulting mphf. The size of packed_mphf must be at least cmph_packed_size() 
+ */
+void brz_pack(cmph_t *mphf, void *packed_mphf)
+{
+	brz_data_t *data = (brz_data_t *)mphf->data;
+	cmph_uint8 * ptr = packed_mphf;
+	cmph_uint32 i,n;
+	
+	// packing internal algo type
+	memcpy(ptr, &(data->algo), sizeof(data->algo));
+	ptr += sizeof(data->algo);
+
+	// packing h0 type
+	CMPH_HASH h0_type = hash_get_type(data->h0); 
+	memcpy(ptr, &h0_type, sizeof(h0_type));
+	ptr += sizeof(h0_type);
+
+	// packing h0
+	hash_state_pack(data->h0, ptr);
+	ptr += hash_state_packed_size(h0_type);
+	
+	// packing k
+	memcpy(ptr, &(data->k), sizeof(data->k));
+	ptr += sizeof(data->k);
+
+	// packing c
+	*((cmph_uint64 *)ptr) = (cmph_uint64)data->c; 
+	ptr += sizeof(data->c);
+
+	// packing h1 type
+	CMPH_HASH h1_type = hash_get_type(data->h1[0]); 
+	memcpy(ptr, &h1_type, sizeof(h1_type));
+	ptr += sizeof(h1_type);
+
+	// packing h2 type
+	CMPH_HASH h2_type = hash_get_type(data->h2[0]); 
+	memcpy(ptr, &h2_type, sizeof(h2_type));
+	ptr += sizeof(h2_type);
+
+	// packing size
+	memcpy(ptr, data->size, sizeof(cmph_uint8)*data->k);	
+	ptr += data->k;
+	
+	// packing offset
+	memcpy(ptr, data->offset, sizeof(cmph_uint32)*data->k);	
+	ptr += sizeof(cmph_uint32)*data->k;
+	
+	#if defined (__ia64) || defined (__x86_64__)
+		cmph_uint64 * g_is_ptr = (cmph_uint64 *)ptr;
+	#else
+		cmph_uint32 * g_is_ptr = (cmph_uint32 *)ptr;
+	#endif
+	
+	cmph_uint8 * g_i = (cmph_uint8 *) (g_is_ptr + data->k);
+	
+	for(i = 0; i < data->k; i++)
+	{
+		#if defined (__ia64) || defined (__x86_64__)
+			*g_is_ptr++ = (cmph_uint64)g_i;
+		#else
+			*g_is_ptr++ = (cmph_uint32)g_i;
+		#endif
+		// packing h1[i]
+		hash_state_pack(data->h1[i], g_i);
+		g_i += hash_state_packed_size(h1_type);
+		
+		// packing h2[i]
+		hash_state_pack(data->h2[i], g_i);
+		g_i += hash_state_packed_size(h2_type);
+
+		// packing g_i
+		switch(data->algo)
+		{
+			case CMPH_FCH:
+				n = fch_calc_b(data->c, data->size[i]);
+				break;
+			case CMPH_BMZ8:
+				n = (cmph_uint32)ceil(data->c * data->size[i]);
+				break;
+			default: assert(0);
+		}
+		memcpy(g_i, data->g[i], sizeof(cmph_uint8)*n);	
+		g_i += n;
+		
+	}
+
+}
+
+/** \fn cmph_uint32 brz_packed_size(cmph_t *mphf);
+ *  \brief Return the amount of space needed to pack mphf.
+ *  \param mphf pointer to a mphf
+ *  \return the size of the packed function or zero for failures
+ */ 
+cmph_uint32 brz_packed_size(cmph_t *mphf)
+{
+	cmph_uint32 i;
+	cmph_uint32 size = 0;
+	brz_data_t *data = (brz_data_t *)mphf->data;
+	CMPH_HASH h0_type = hash_get_type(data->h0); 
+	CMPH_HASH h1_type = hash_get_type(data->h1[0]); 
+	CMPH_HASH h2_type = hash_get_type(data->h2[0]);
+	size = (cmph_uint32)(2*sizeof(CMPH_ALGO) + 3*sizeof(CMPH_HASH) + hash_state_packed_size(h0_type) + sizeof(cmph_uint32) + 
+			sizeof(double) + sizeof(cmph_uint8)*data->k + sizeof(cmph_uint32)*data->k);
+	// pointers to g_is
+	#if defined (__ia64) || defined (__x86_64__)
+		size +=  (cmph_uint32) sizeof(cmph_uint64)*data->k;
+	#else
+		size +=  (cmph_uint32) sizeof(cmph_uint32)*data->k;
+	#endif
+	
+	size += hash_state_packed_size(h1_type) * data->k;
+	size += hash_state_packed_size(h2_type) * data->k;
+	
+	cmph_uint32 n = 0;
+	for(i = 0; i < data->k; i++)
+	{
+   		switch(data->algo)
+   		{
+   			case CMPH_FCH:
+   				n = fch_calc_b(data->c, data->size[i]);
+   				break;
+   			case CMPH_BMZ8:
+   				n = (cmph_uint32)ceil(data->c * data->size[i]);
+   				break;
+   			default: assert(0);
+   		}
+		size += n;	
+	}
+	return size;
+}
+
+
+
+static cmph_uint32 brz_bmz8_search_packed(cmph_uint32 *packed_mphf, const char *key, cmph_uint32 keylen, cmph_uint32 * fingerprint)
+{
+	register CMPH_HASH h0_type = *packed_mphf++;
+	register cmph_uint32 *h0_ptr = packed_mphf;
+	packed_mphf = (cmph_uint32 *)(((cmph_uint8 *)packed_mphf) + hash_state_packed_size(h0_type)); 
+	
+	register cmph_uint32 k = *packed_mphf++;
+
+	register double c = (double)(*((cmph_uint64*)packed_mphf));
+	packed_mphf += 2;
+
+	register CMPH_HASH h1_type = *packed_mphf++; 
+	
+	register CMPH_HASH h2_type = *packed_mphf++; 
+
+	register cmph_uint8 * size = (cmph_uint8 *) packed_mphf;
+	packed_mphf = (cmph_uint32 *)(size + k);  
+	
+	register cmph_uint32 * offset = packed_mphf;
+	packed_mphf += k;
+
+	register cmph_uint32 h0;
+	
+	hash_vector_packed(h0_ptr, h0_type, key, keylen, fingerprint);
+	h0 = fingerprint[2] % k;
+	
+	register cmph_uint32 m = size[h0];
+	register cmph_uint32 n = (cmph_uint32)ceil(c * m);
+
+	#if defined (__ia64) || defined (__x86_64__)
+		register cmph_uint64 * g_is_ptr = (cmph_uint64 *)packed_mphf;
+	#else
+		register cmph_uint32 * g_is_ptr = packed_mphf;
+	#endif
+	
+	register cmph_uint8 * h1_ptr = (cmph_uint8 *) g_is_ptr[h0];
+	
+	register cmph_uint8 * h2_ptr = h1_ptr + hash_state_packed_size(h1_type);
+
+	register cmph_uint8 * g = h2_ptr + hash_state_packed_size(h2_type);
+	
+	register cmph_uint32 h1 = hash_packed(h1_ptr, h1_type, key, keylen) % n;
+	register cmph_uint32 h2 = hash_packed(h2_ptr, h2_type, key, keylen) % n;
+
+	register cmph_uint8 mphf_bucket;
+		
+	if (h1 == h2 && ++h2 >= n) h2 = 0;
+	mphf_bucket = (cmph_uint8)(g[h1] + g[h2]); 
+	DEBUGP("key: %s h1: %u h2: %u h0: %u\n", key, h1, h2, h0);
+	DEBUGP("Address: %u\n", mphf_bucket + offset[h0]);
+	return (mphf_bucket + offset[h0]);	
+}
+
+static cmph_uint32 brz_fch_search_packed(cmph_uint32 *packed_mphf, const char *key, cmph_uint32 keylen, cmph_uint32 * fingerprint)
+{
+	register CMPH_HASH h0_type = *packed_mphf++;
+	
+	register cmph_uint32 *h0_ptr = packed_mphf;
+	packed_mphf = (cmph_uint32 *)(((cmph_uint8 *)packed_mphf) + hash_state_packed_size(h0_type)); 
+	
+	register cmph_uint32 k = *packed_mphf++;
+
+	register double c = (double)(*((cmph_uint64*)packed_mphf));
+	packed_mphf += 2;
+
+	register CMPH_HASH h1_type = *packed_mphf++; 
+
+	register CMPH_HASH h2_type = *packed_mphf++; 
+
+	register cmph_uint8 * size = (cmph_uint8 *) packed_mphf;
+	packed_mphf = (cmph_uint32 *)(size + k);  
+	
+	register cmph_uint32 * offset = packed_mphf;
+	packed_mphf += k;
+	
+	register cmph_uint32 h0;
+	
+	hash_vector_packed(h0_ptr, h0_type, key, keylen, fingerprint);
+	h0 = fingerprint[2] % k;
+	
+	register cmph_uint32 m = size[h0];
+	register cmph_uint32 b = fch_calc_b(c, m);
+	register double p1 = fch_calc_p1(m);
+	register double p2 = fch_calc_p2(b);
+	
+	#if defined (__ia64) || defined (__x86_64__)
+		register cmph_uint64 * g_is_ptr = (cmph_uint64 *)packed_mphf;
+	#else
+		register cmph_uint32 * g_is_ptr = packed_mphf;
+	#endif
+	
+	register cmph_uint8 * h1_ptr = (cmph_uint8 *) g_is_ptr[h0];
+	
+	register cmph_uint8 * h2_ptr = h1_ptr + hash_state_packed_size(h1_type);
+
+	register cmph_uint8 * g = h2_ptr + hash_state_packed_size(h2_type);
+	
+	register cmph_uint32 h1 = hash_packed(h1_ptr, h1_type, key, keylen) % m;
+	register cmph_uint32 h2 = hash_packed(h2_ptr, h2_type, key, keylen) % m;
+
+	register cmph_uint8 mphf_bucket = 0;
+	h1 = mixh10h11h12(b, p1, p2, h1);
+	mphf_bucket = (cmph_uint8)((h2 + g[h1]) % m);
+	return (mphf_bucket + offset[h0]);
+}
+
+/** cmph_uint32 brz_search(void *packed_mphf, const char *key, cmph_uint32 keylen);
+ *  \brief Use the packed mphf to do a search. 
+ *  \param  packed_mphf pointer to the packed mphf
+ *  \param key key to be hashed
+ *  \param keylen key legth in bytes
+ *  \return The mphf value
+ */
+cmph_uint32 brz_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen)
+{
+	register cmph_uint32 *ptr = (cmph_uint32 *)packed_mphf;	
+	register CMPH_ALGO algo = *ptr++;
+	cmph_uint32 fingerprint[3];
+	switch(algo)
+	{
+		case CMPH_FCH:
+			return brz_fch_search_packed(ptr, key, keylen, fingerprint);
+		case CMPH_BMZ8:
+			return brz_bmz8_search_packed(ptr, key, keylen, fingerprint);
+		default: assert(0);
+	}
+}
+
diff --git a/girepository/cmph/brz.h b/girepository/cmph/brz.h
new file mode 100644
index 0000000..ac07ed7
--- /dev/null
+++ b/girepository/cmph/brz.h
@@ -0,0 +1,47 @@
+#ifndef __CMPH_BRZ_H__
+#define __CMPH_BRZ_H__
+
+#include "cmph.h"
+
+typedef struct __brz_data_t brz_data_t;
+typedef struct __brz_config_data_t brz_config_data_t;
+
+brz_config_data_t *brz_config_new();
+void brz_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs);
+void brz_config_set_tmp_dir(cmph_config_t *mph, cmph_uint8 *tmp_dir);
+void brz_config_set_mphf_fd(cmph_config_t *mph, FILE *mphf_fd);
+void brz_config_set_b(cmph_config_t *mph, cmph_uint32 b);
+void brz_config_set_algo(cmph_config_t *mph, CMPH_ALGO algo);
+void brz_config_set_memory_availability(cmph_config_t *mph, cmph_uint32 memory_availability);
+void brz_config_destroy(cmph_config_t *mph);
+cmph_t *brz_new(cmph_config_t *mph, double c);
+
+void brz_load(FILE *f, cmph_t *mphf);
+int brz_dump(cmph_t *mphf, FILE *f);
+void brz_destroy(cmph_t *mphf);
+cmph_uint32 brz_search(cmph_t *mphf, const char *key, cmph_uint32 keylen);
+
+/** \fn void brz_pack(cmph_t *mphf, void *packed_mphf);
+ *  \brief Support the ability to pack a perfect hash function into a preallocated contiguous memory space pointed by packed_mphf.
+ *  \param mphf pointer to the resulting mphf
+ *  \param packed_mphf pointer to the contiguous memory area used to store the resulting mphf. The size of packed_mphf must be at least cmph_packed_size() 
+ */
+void brz_pack(cmph_t *mphf, void *packed_mphf);
+
+/** \fn cmph_uint32 brz_packed_size(cmph_t *mphf);
+ *  \brief Return the amount of space needed to pack mphf.
+ *  \param mphf pointer to a mphf
+ *  \return the size of the packed function or zero for failures
+ */ 
+cmph_uint32 brz_packed_size(cmph_t *mphf);
+
+/** cmph_uint32 brz_search(void *packed_mphf, const char *key, cmph_uint32 keylen);
+ *  \brief Use the packed mphf to do a search. 
+ *  \param  packed_mphf pointer to the packed mphf
+ *  \param key key to be hashed
+ *  \param keylen key legth in bytes
+ *  \return The mphf value
+ */
+cmph_uint32 brz_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen);
+
+#endif
diff --git a/girepository/cmph/brz_structs.h b/girepository/cmph/brz_structs.h
new file mode 100755
index 0000000..b781107
--- /dev/null
+++ b/girepository/cmph/brz_structs.h
@@ -0,0 +1,39 @@
+#ifndef __CMPH_BRZ_STRUCTS_H__
+#define __CMPH_BRZ_STRUCTS_H__
+
+#include "hash_state.h"
+
+struct __brz_data_t
+{
+	CMPH_ALGO algo;      // CMPH algo for generating the MPHFs for the buckets (Just CMPH_FCH and CMPH_BMZ8)
+	cmph_uint32 m;       // edges (words) count
+	double c;      // constant c
+	cmph_uint8  *size;   // size[i] stores the number of edges represented by g[i][...]. 
+	cmph_uint32 *offset; // offset[i] stores the sum: size[0] + size[1] + ... size[i-1].
+	cmph_uint8 **g;      // g function. 
+	cmph_uint32 k;       // number of components
+	hash_state_t **h1;
+	hash_state_t **h2;
+	hash_state_t * h0;
+};
+
+struct __brz_config_data_t
+{
+	CMPH_HASH hashfuncs[3];
+	CMPH_ALGO algo;      // CMPH algo for generating the MPHFs for the buckets (Just CMPH_FCH and CMPH_BMZ8)
+	double c;      // constant c
+	cmph_uint32 m;       // edges (words) count
+	cmph_uint8  *size;   // size[i] stores the number of edges represented by g[i][...]. 
+	cmph_uint32 *offset; // offset[i] stores the sum: size[0] + size[1] + ... size[i-1].
+	cmph_uint8 **g;      // g function. 
+	cmph_uint8  b;       // parameter b. 
+	cmph_uint32 k;       // number of components
+	hash_state_t **h1;
+	hash_state_t **h2;
+	hash_state_t * h0;    
+	cmph_uint32 memory_availability; 
+	cmph_uint8 * tmp_dir; // temporary directory 
+	FILE * mphf_fd; // mphf file
+};
+
+#endif
diff --git a/girepository/cmph/buffer_entry.c b/girepository/cmph/buffer_entry.c
new file mode 100644
index 0000000..7f82aae
--- /dev/null
+++ b/girepository/cmph/buffer_entry.c
@@ -0,0 +1,103 @@
+#include "buffer_entry.h"
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct __buffer_entry_t
+{
+	FILE *fd;
+	cmph_uint8 * buff;
+	cmph_uint32 capacity, // buffer entry capacity
+		    nbytes,   // buffer entry used bytes
+		    pos;      // current read position in buffer entry
+	cmph_uint8  eof;      // flag to indicate end of file
+};
+
+buffer_entry_t * buffer_entry_new(cmph_uint32 capacity)
+{
+	buffer_entry_t *buff_entry = (buffer_entry_t *)malloc(sizeof(buffer_entry_t));
+	assert(buff_entry);
+	buff_entry->fd = NULL;
+	buff_entry->buff = NULL;
+	buff_entry->capacity = capacity;
+	buff_entry->nbytes = capacity;
+	buff_entry->pos = capacity;
+        buff_entry->eof = 0;
+	return buff_entry;
+}
+
+void buffer_entry_open(buffer_entry_t * buffer_entry, char * filename)
+{
+	buffer_entry->fd = fopen(filename, "rb");
+}
+
+void buffer_entry_set_capacity(buffer_entry_t * buffer_entry, cmph_uint32 capacity)
+{
+	buffer_entry->capacity = capacity;
+}
+
+
+cmph_uint32 buffer_entry_get_capacity(buffer_entry_t * buffer_entry)
+{
+	return buffer_entry->capacity;
+}
+
+void buffer_entry_load(buffer_entry_t * buffer_entry)
+{
+	free(buffer_entry->buff);
+	buffer_entry->buff = (cmph_uint8 *)calloc((size_t)buffer_entry->capacity, sizeof(cmph_uint8));
+	buffer_entry->nbytes = (cmph_uint32)fread(buffer_entry->buff, (size_t)1, (size_t)buffer_entry->capacity, buffer_entry->fd);
+	if (buffer_entry->nbytes != buffer_entry->capacity) buffer_entry->eof = 1;
+	buffer_entry->pos = 0;
+}
+
+cmph_uint8 * buffer_entry_read_key(buffer_entry_t * buffer_entry, cmph_uint32 * keylen)
+{
+	cmph_uint8 * buf = NULL;
+	cmph_uint32 lacked_bytes = sizeof(*keylen);
+	cmph_uint32 copied_bytes = 0;
+	if(buffer_entry->eof && (buffer_entry->pos == buffer_entry->nbytes)) // end
+	{
+		free(buf);
+		return NULL;
+	}
+	if((buffer_entry->pos + lacked_bytes) > buffer_entry->nbytes) 
+	{
+		copied_bytes = buffer_entry->nbytes - buffer_entry->pos;
+		lacked_bytes = (buffer_entry->pos + lacked_bytes) - buffer_entry->nbytes;
+		if (copied_bytes != 0) memcpy(keylen, buffer_entry->buff + buffer_entry->pos, (size_t)copied_bytes);
+		buffer_entry_load(buffer_entry);
+	}
+	memcpy(keylen + copied_bytes, buffer_entry->buff + buffer_entry->pos, (size_t)lacked_bytes);
+	buffer_entry->pos += lacked_bytes;
+	
+	lacked_bytes = *keylen;
+	copied_bytes = 0;
+	buf = (cmph_uint8 *)malloc(*keylen + sizeof(*keylen));
+        memcpy(buf, keylen, sizeof(*keylen));
+	if((buffer_entry->pos + lacked_bytes) > buffer_entry->nbytes) {
+		copied_bytes = buffer_entry->nbytes - buffer_entry->pos;
+		lacked_bytes = (buffer_entry->pos + lacked_bytes) - buffer_entry->nbytes;
+		if (copied_bytes != 0) {
+			memcpy(buf + sizeof(*keylen), buffer_entry->buff + buffer_entry->pos, (size_t)copied_bytes);
+                }
+		buffer_entry_load(buffer_entry);
+	}        
+	memcpy(buf+sizeof(*keylen)+copied_bytes, buffer_entry->buff + buffer_entry->pos, (size_t)lacked_bytes);
+	buffer_entry->pos += lacked_bytes;
+	return buf;
+}
+
+void buffer_entry_destroy(buffer_entry_t * buffer_entry)
+{
+  fclose(buffer_entry->fd);
+  buffer_entry->fd = NULL;
+  free(buffer_entry->buff);
+  buffer_entry->buff = NULL;
+  buffer_entry->capacity = 0;
+  buffer_entry->nbytes = 0;
+  buffer_entry->pos = 0;  
+  buffer_entry->eof = 0;
+  free(buffer_entry);
+}
diff --git a/girepository/cmph/buffer_entry.h b/girepository/cmph/buffer_entry.h
new file mode 100644
index 0000000..62102ba
--- /dev/null
+++ b/girepository/cmph/buffer_entry.h
@@ -0,0 +1,14 @@
+#ifndef __CMPH_BUFFER_ENTRY_H__
+#define __CMPH_BUFFER_ENTRY_H__
+
+#include "cmph_types.h"
+#include <stdio.h>
+typedef struct __buffer_entry_t buffer_entry_t;
+
+buffer_entry_t * buffer_entry_new(cmph_uint32 capacity);
+void buffer_entry_set_capacity(buffer_entry_t * buffer_entry, cmph_uint32 capacity);
+cmph_uint32 buffer_entry_get_capacity(buffer_entry_t * buffer_entry);
+void buffer_entry_open(buffer_entry_t * buffer_entry, char * filename);
+cmph_uint8 * buffer_entry_read_key(buffer_entry_t * buffer_entry, cmph_uint32 * keylen);
+void buffer_entry_destroy(buffer_entry_t * buffer_entry);
+#endif
diff --git a/girepository/cmph/buffer_manage.c b/girepository/cmph/buffer_manage.c
new file mode 100644
index 0000000..fdefc62
--- /dev/null
+++ b/girepository/cmph/buffer_manage.c
@@ -0,0 +1,66 @@
+#include "buffer_manage.h"
+#include "buffer_entry.h"
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+struct __buffer_manage_t
+{
+	cmph_uint32 memory_avail;         // memory available
+	buffer_entry_t ** buffer_entries; // buffer entries to be managed
+	cmph_uint32 nentries;             // number of entries to be managed
+	cmph_uint32 *memory_avail_list;   // memory available list
+	int pos_avail_list;               // current position in memory available list
+};
+
+buffer_manage_t * buffer_manage_new(cmph_uint32 memory_avail, cmph_uint32 nentries)
+{
+	cmph_uint32 memory_avail_entry, i;
+	buffer_manage_t *buff_manage = (buffer_manage_t *)malloc(sizeof(buffer_manage_t));
+	assert(buff_manage);
+	buff_manage->memory_avail = memory_avail;
+	buff_manage->buffer_entries = (buffer_entry_t **)calloc((size_t)nentries, sizeof(buffer_entry_t *));
+	buff_manage->memory_avail_list = (cmph_uint32 *)calloc((size_t)nentries, sizeof(cmph_uint32));
+	buff_manage->pos_avail_list = -1;
+	buff_manage->nentries = nentries;
+	memory_avail_entry = buff_manage->memory_avail/buff_manage->nentries + 1;
+	for(i = 0; i < buff_manage->nentries; i++)
+	{
+		buff_manage->buffer_entries[i] = buffer_entry_new(memory_avail_entry);
+	}	
+	return buff_manage;
+}
+
+void buffer_manage_open(buffer_manage_t * buffer_manage, cmph_uint32 index, char * filename)
+{
+	buffer_entry_open(buffer_manage->buffer_entries[index], filename);
+}
+
+cmph_uint8 * buffer_manage_read_key(buffer_manage_t * buffer_manage, cmph_uint32 index)
+{
+	cmph_uint8 * key = NULL;
+	if (buffer_manage->pos_avail_list >= 0 ) // recovering memory
+	{
+		cmph_uint32 new_capacity = buffer_entry_get_capacity(buffer_manage->buffer_entries[index]) + buffer_manage->memory_avail_list[(buffer_manage->pos_avail_list)--];
+		buffer_entry_set_capacity(buffer_manage->buffer_entries[index], new_capacity);
+		//fprintf(stderr, "recovering memory\n");
+	}
+	key = buffer_entry_read_key(buffer_manage->buffer_entries[index]);
+	if (key == NULL) // storing memory to be recovered
+	{
+		buffer_manage->memory_avail_list[++(buffer_manage->pos_avail_list)] = buffer_entry_get_capacity(buffer_manage->buffer_entries[index]);
+		//fprintf(stderr, "storing memory to be recovered\n");
+	}
+	return key;
+}
+
+void buffer_manage_destroy(buffer_manage_t * buffer_manage)
+{ 
+	cmph_uint32 i;
+	for(i = 0; i < buffer_manage->nentries; i++)
+	{
+		buffer_entry_destroy(buffer_manage->buffer_entries[i]);
+	}
+	free(buffer_manage->memory_avail_list);
+	free(buffer_manage->buffer_entries);
+	free(buffer_manage);
+}
diff --git a/girepository/cmph/buffer_manage.h b/girepository/cmph/buffer_manage.h
new file mode 100644
index 0000000..8c66cff
--- /dev/null
+++ b/girepository/cmph/buffer_manage.h
@@ -0,0 +1,12 @@
+#ifndef __CMPH_BUFFER_MANAGE_H__
+#define __CMPH_BUFFER_MANAGE_H__
+
+#include "cmph_types.h"
+#include <stdio.h>
+typedef struct __buffer_manage_t buffer_manage_t;
+
+buffer_manage_t * buffer_manage_new(cmph_uint32 memory_avail, cmph_uint32 nentries);
+void buffer_manage_open(buffer_manage_t * buffer_manage, cmph_uint32 index, char * filename);
+cmph_uint8 * buffer_manage_read_key(buffer_manage_t * buffer_manage, cmph_uint32 index);
+void buffer_manage_destroy(buffer_manage_t * buffer_manage);
+#endif
diff --git a/girepository/cmph/buffer_manager.c b/girepository/cmph/buffer_manager.c
new file mode 100644
index 0000000..5a051e2
--- /dev/null
+++ b/girepository/cmph/buffer_manager.c
@@ -0,0 +1,64 @@
+#include "buffer_manager.h"
+#include "buffer_entry.h"
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+struct __buffer_manager_t
+{
+	cmph_uint32 memory_avail;         // memory available
+	buffer_entry_t ** buffer_entries; // buffer entries to be managed
+	cmph_uint32 nentries;             // number of entries to be managed
+	cmph_uint32 *memory_avail_list;   // memory available list
+	int pos_avail_list;               // current position in memory available list
+};
+
+buffer_manager_t * buffer_manager_new(cmph_uint32 memory_avail, cmph_uint32 nentries)
+{
+	cmph_uint32 memory_avail_entry, i;
+	buffer_manager_t *buff_manager = (buffer_manager_t *)malloc(sizeof(buffer_manager_t));
+	assert(buff_manager);
+	buff_manager->memory_avail = memory_avail;
+	buff_manager->buffer_entries = (buffer_entry_t **)calloc((size_t)nentries, sizeof(buffer_entry_t *));
+	buff_manager->memory_avail_list = (cmph_uint32 *)calloc((size_t)nentries, sizeof(cmph_uint32));
+	buff_manager->pos_avail_list = -1;
+	buff_manager->nentries = nentries;
+	memory_avail_entry = buff_manager->memory_avail/buff_manager->nentries + 1;
+	for(i = 0; i < buff_manager->nentries; i++)
+	{
+		buff_manager->buffer_entries[i] = buffer_entry_new(memory_avail_entry);
+	}	
+	return buff_manager;
+}
+
+void buffer_manager_open(buffer_manager_t * buffer_manager, cmph_uint32 index, char * filename)
+{
+	buffer_entry_open(buffer_manager->buffer_entries[index], filename);
+}
+
+cmph_uint8 * buffer_manager_read_key(buffer_manager_t * buffer_manager, cmph_uint32 index, cmph_uint32 * keylen)
+{
+	cmph_uint8 * key = NULL;
+	if (buffer_manager->pos_avail_list >= 0 ) // recovering memory
+	{
+		cmph_uint32 new_capacity = buffer_entry_get_capacity(buffer_manager->buffer_entries[index]) + buffer_manager->memory_avail_list[(buffer_manager->pos_avail_list)--];
+		buffer_entry_set_capacity(buffer_manager->buffer_entries[index], new_capacity);
+	}
+	key = buffer_entry_read_key(buffer_manager->buffer_entries[index], keylen);
+	if (key == NULL) // storing memory to be recovered
+	{
+		buffer_manager->memory_avail_list[++(buffer_manager->pos_avail_list)] = buffer_entry_get_capacity(buffer_manager->buffer_entries[index]);
+	}
+	return key;
+}
+
+void buffer_manager_destroy(buffer_manager_t * buffer_manager)
+{ 
+	cmph_uint32 i;
+	for(i = 0; i < buffer_manager->nentries; i++)
+	{
+		buffer_entry_destroy(buffer_manager->buffer_entries[i]);
+	}
+	free(buffer_manager->memory_avail_list);
+	free(buffer_manager->buffer_entries);
+	free(buffer_manager);
+}
diff --git a/girepository/cmph/buffer_manager.h b/girepository/cmph/buffer_manager.h
new file mode 100644
index 0000000..af99c20
--- /dev/null
+++ b/girepository/cmph/buffer_manager.h
@@ -0,0 +1,12 @@
+#ifndef __CMPH_BUFFER_MANAGE_H__
+#define __CMPH_BUFFER_MANAGE_H__
+
+#include "cmph_types.h"
+#include <stdio.h>
+typedef struct __buffer_manager_t buffer_manager_t;
+
+buffer_manager_t * buffer_manager_new(cmph_uint32 memory_avail, cmph_uint32 nentries);
+void buffer_manager_open(buffer_manager_t * buffer_manager, cmph_uint32 index, char * filename);
+cmph_uint8 * buffer_manager_read_key(buffer_manager_t * buffer_manager, cmph_uint32 index, cmph_uint32 * keylen);
+void buffer_manager_destroy(buffer_manager_t * buffer_manager);
+#endif
diff --git a/girepository/cmph/chd.c b/girepository/cmph/chd.c
new file mode 100644
index 0000000..7fb3b8b
--- /dev/null
+++ b/girepository/cmph/chd.c
@@ -0,0 +1,271 @@
+#include<stdio.h>
+#include<stdlib.h>
+#include<string.h>
+#include<math.h>
+#include<time.h>
+#include<assert.h>
+#include<limits.h>
+
+#include "cmph_structs.h"
+#include "chd_structs.h"
+#include "chd.h"
+#include "bitbool.h"
+//#define DEBUG
+#include "debug.h"
+
+chd_config_data_t *chd_config_new(cmph_config_t *mph)
+{
+	cmph_io_adapter_t *key_source = mph->key_source;
+	chd_config_data_t *chd;
+	chd = (chd_config_data_t *)malloc(sizeof(chd_config_data_t));
+	assert(chd);
+	memset(chd, 0, sizeof(chd_config_data_t));
+
+	chd->chd_ph = cmph_config_new(key_source);
+	cmph_config_set_algo(chd->chd_ph, CMPH_CHD_PH);
+
+	return chd;
+}
+
+void chd_config_destroy(cmph_config_t *mph)
+{
+	chd_config_data_t *data = (chd_config_data_t *) mph->data;
+	DEBUGP("Destroying algorithm dependent data\n");
+	if(data->chd_ph)
+	{
+		cmph_config_destroy(data->chd_ph);
+		data->chd_ph = NULL;
+	}
+	free(data);
+}
+
+
+void chd_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs)
+{
+	chd_config_data_t *data = (chd_config_data_t *) mph->data;
+	cmph_config_set_hashfuncs(data->chd_ph, hashfuncs);
+}
+
+
+void chd_config_set_b(cmph_config_t *mph, cmph_uint32 keys_per_bucket)
+{
+	chd_config_data_t *data = (chd_config_data_t *) mph->data;
+	cmph_config_set_b(data->chd_ph, keys_per_bucket);
+}
+
+
+void chd_config_set_keys_per_bin(cmph_config_t *mph, cmph_uint32 keys_per_bin)
+{
+	chd_config_data_t *data = (chd_config_data_t *) mph->data;
+	cmph_config_set_keys_per_bin(data->chd_ph, keys_per_bin);
+}
+
+
+cmph_t *chd_new(cmph_config_t *mph, double c)
+{
+	cmph_t *mphf = NULL;
+	chd_data_t *chdf = NULL;
+	chd_config_data_t *chd = (chd_config_data_t *)mph->data;
+	chd_ph_config_data_t * chd_ph = (chd_ph_config_data_t *)chd->chd_ph->data;
+	compressed_rank_t cr;
+	
+	register cmph_t * chd_phf = NULL;
+	register cmph_uint32 packed_chd_phf_size = 0; 
+	cmph_uint8 * packed_chd_phf = NULL;
+	
+	register cmph_uint32 packed_cr_size = 0; 
+	cmph_uint8 * packed_cr = NULL;
+
+	register cmph_uint32 i, idx, nkeys, nvals, nbins;
+	cmph_uint32 * vals_table = NULL;
+	register cmph_uint32 * occup_table = NULL;
+	#ifdef CMPH_TIMING
+	double construction_time_begin = 0.0;
+	double construction_time = 0.0;
+	ELAPSED_TIME_IN_SECONDS(&construction_time_begin);
+	#endif
+
+	cmph_config_set_verbosity(chd->chd_ph, mph->verbosity);	
+	cmph_config_set_graphsize(chd->chd_ph, c);
+	
+	if (mph->verbosity)
+	{
+		fprintf(stderr, "Generating a CHD_PH perfect hash function with a load factor equal to %.3f\n", c);
+	}
+	
+	chd_phf = cmph_new(chd->chd_ph);
+	
+	if(chd_phf == NULL) 
+	{
+		return NULL;
+	}
+	
+	packed_chd_phf_size = cmph_packed_size(chd_phf); 
+	DEBUGP("packed_chd_phf_size = %u\n", packed_chd_phf_size);
+	
+	/* Make sure that we have enough space to pack the mphf. */
+	packed_chd_phf = calloc((size_t)packed_chd_phf_size,(size_t)1);
+
+	/* Pack the mphf. */
+	cmph_pack(chd_phf, packed_chd_phf);
+
+	cmph_destroy(chd_phf);
+	
+	
+	if (mph->verbosity)
+	{
+		fprintf(stderr, "Compressing the range of the resulting CHD_PH perfect hash function\n");
+	}
+
+	compressed_rank_init(&cr);
+	nbins = chd_ph->n;
+	nkeys = chd_ph->m;
+	nvals =  nbins - nkeys; 
+	
+	vals_table = (cmph_uint32 *)calloc(nvals, sizeof(cmph_uint32));
+	occup_table = (cmph_uint32 *)chd_ph->occup_table;
+	
+	for(i = 0, idx = 0; i < nbins; i++)
+	{
+		if(!GETBIT32(occup_table, i))
+		{
+			vals_table[idx++] = i;
+		}
+	}
+	
+	compressed_rank_generate(&cr, vals_table, nvals);
+	free(vals_table);
+	
+	packed_cr_size = compressed_rank_packed_size(&cr);
+	packed_cr = (cmph_uint8 *) calloc(packed_cr_size, sizeof(cmph_uint8));
+	compressed_rank_pack(&cr, packed_cr);
+	compressed_rank_destroy(&cr);
+
+	mphf = (cmph_t *)malloc(sizeof(cmph_t));
+	mphf->algo = mph->algo;
+	chdf = (chd_data_t *)malloc(sizeof(chd_data_t));
+	
+	chdf->packed_cr = packed_cr;
+	packed_cr = NULL; //transfer memory ownership
+
+	chdf->packed_chd_phf = packed_chd_phf;
+	packed_chd_phf = NULL; //transfer memory ownership
+	
+	chdf->packed_chd_phf_size = packed_chd_phf_size;
+	chdf->packed_cr_size = packed_cr_size;
+	
+	mphf->data = chdf;
+	mphf->size = nkeys;
+
+	DEBUGP("Successfully generated minimal perfect hash\n");
+	if (mph->verbosity)
+	{
+		fprintf(stderr, "Successfully generated minimal perfect hash function\n");
+	}
+	#ifdef CMPH_TIMING	
+	ELAPSED_TIME_IN_SECONDS(&construction_time);
+	register cmph_uint32 space_usage =  chd_packed_size(mphf)*8;
+	construction_time = construction_time - construction_time_begin;
+	fprintf(stdout, "%u\t%.2f\t%u\t%.4f\t%.4f\n", nkeys, c, chd_ph->keys_per_bucket, construction_time, space_usage/(double)nkeys);
+	#endif	
+
+	return mphf;
+}
+
+void chd_load(FILE *fd, cmph_t *mphf)
+{
+	register size_t nbytes;
+	chd_data_t *chd = (chd_data_t *)malloc(sizeof(chd_data_t));
+
+	DEBUGP("Loading chd mphf\n");
+	mphf->data = chd;
+
+	nbytes = fread(&chd->packed_chd_phf_size, sizeof(cmph_uint32), (size_t)1, fd);
+	DEBUGP("Loading CHD_PH perfect hash function with %u bytes to disk\n", chd->packed_chd_phf_size);
+	chd->packed_chd_phf = (cmph_uint8 *) calloc((size_t)chd->packed_chd_phf_size,(size_t)1);
+	nbytes = fread(chd->packed_chd_phf, chd->packed_chd_phf_size, (size_t)1, fd);
+
+	nbytes = fread(&chd->packed_cr_size, sizeof(cmph_uint32), (size_t)1, fd);
+	DEBUGP("Loading Compressed rank structure, which has %u bytes\n", chd->packed_cr_size);
+	chd->packed_cr = (cmph_uint8 *) calloc((size_t)chd->packed_cr_size, (size_t)1);
+	nbytes = fread(chd->packed_cr, chd->packed_cr_size, (size_t)1, fd);
+}
+
+int chd_dump(cmph_t *mphf, FILE *fd)
+{
+	register size_t nbytes;
+	chd_data_t *data = (chd_data_t *)mphf->data;
+	
+	__cmph_dump(mphf, fd);
+	// Dumping CHD_PH perfect hash function
+
+	DEBUGP("Dumping CHD_PH perfect hash function with %u bytes to disk\n", data->packed_chd_phf_size);
+	nbytes = fwrite(&data->packed_chd_phf_size, sizeof(cmph_uint32), (size_t)1, fd);
+	nbytes = fwrite(data->packed_chd_phf, data->packed_chd_phf_size, (size_t)1, fd);
+
+	DEBUGP("Dumping compressed rank structure with %u bytes to disk\n", buflen);
+	nbytes = fwrite(&data->packed_cr_size, sizeof(cmph_uint32), (size_t)1, fd);
+	nbytes = fwrite(data->packed_cr, data->packed_cr_size, (size_t)1, fd);
+	
+	return 1;
+}
+
+void chd_destroy(cmph_t *mphf)
+{
+	chd_data_t *data = (chd_data_t *)mphf->data;
+	free(data->packed_chd_phf);
+	free(data->packed_cr);
+	free(data);
+	free(mphf);
+}
+
+static inline cmph_uint32 _chd_search(void * packed_chd_phf, void * packed_cr, const char *key, cmph_uint32 keylen)
+{
+	register cmph_uint32 bin_idx = cmph_search_packed(packed_chd_phf, key, keylen);
+	register cmph_uint32 rank = compressed_rank_query_packed(packed_cr, bin_idx);
+	return bin_idx - rank;
+}
+
+cmph_uint32 chd_search(cmph_t *mphf, const char *key, cmph_uint32 keylen)
+{
+	register chd_data_t * chd = mphf->data;
+	return _chd_search(chd->packed_chd_phf, chd->packed_cr, key, keylen);
+}
+
+void chd_pack(cmph_t *mphf, void *packed_mphf)
+{
+	chd_data_t *data = (chd_data_t *)mphf->data;
+	cmph_uint32 * ptr = packed_mphf;
+	cmph_uint8 * ptr8;
+
+	// packing packed_cr_size and packed_cr
+	*ptr = data->packed_cr_size;
+	ptr8 =  (cmph_uint8 *) (ptr + 1);
+	
+	memcpy(ptr8, data->packed_cr, data->packed_cr_size);
+	ptr8 += data->packed_cr_size;
+	
+	ptr = (cmph_uint32 *) ptr8;
+	*ptr = data->packed_chd_phf_size;
+
+	ptr8 =  (cmph_uint8 *) (ptr + 1);
+	memcpy(ptr8, data->packed_chd_phf, data->packed_chd_phf_size);
+}
+
+cmph_uint32 chd_packed_size(cmph_t *mphf)
+{
+	register chd_data_t *data = (chd_data_t *)mphf->data;
+	return (cmph_uint32)(sizeof(CMPH_ALGO) + 2*sizeof(cmph_uint32) + data->packed_cr_size + data->packed_chd_phf_size);
+
+}
+
+cmph_uint32 chd_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen)
+{
+
+	register cmph_uint32 * ptr = packed_mphf;
+	register cmph_uint32 packed_cr_size = *ptr++;
+	register cmph_uint8 * packed_chd_phf = ((cmph_uint8 *) ptr) + packed_cr_size + sizeof(cmph_uint32);
+	return _chd_search(packed_chd_phf, ptr, key, keylen);
+}
+
+
diff --git a/girepository/cmph/chd.h b/girepository/cmph/chd.h
new file mode 100644
index 0000000..e829df8
--- /dev/null
+++ b/girepository/cmph/chd.h
@@ -0,0 +1,59 @@
+#ifndef _CMPH_CHD_H__
+#define _CMPH_CHD_H__
+
+#include "cmph.h"
+
+typedef struct __chd_data_t chd_data_t;
+typedef struct __chd_config_data_t chd_config_data_t;
+
+/* Config API */
+chd_config_data_t *chd_config_new(cmph_config_t * mph);
+void chd_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs);
+
+/** \fn void chd_config_set_keys_per_bin(cmph_config_t *mph, cmph_uint32 keys_per_bin);
+ *  \brief Allows to set the number of keys per bin.
+ *  \param mph pointer to the configuration structure
+ *  \param keys_per_bin value for the number of keys per bin 
+ */
+void chd_config_set_keys_per_bin(cmph_config_t *mph, cmph_uint32 keys_per_bin);
+
+/** \fn void chd_config_set_b(cmph_config_t *mph, cmph_uint32 keys_per_bucket);
+ *  \brief Allows to set the number of keys per bucket.
+ *  \param mph pointer to the configuration structure
+ *  \param keys_per_bucket value for the number of keys per bucket 
+ */
+void chd_config_set_b(cmph_config_t *mph, cmph_uint32 keys_per_bucket);
+void chd_config_destroy(cmph_config_t *mph);
+
+
+/* Chd algorithm API */
+cmph_t *chd_new(cmph_config_t *mph, double c);
+void chd_load(FILE *fd, cmph_t *mphf);
+int chd_dump(cmph_t *mphf, FILE *fd);
+void chd_destroy(cmph_t *mphf);
+cmph_uint32 chd_search(cmph_t *mphf, const char *key, cmph_uint32 keylen);
+
+/** \fn void chd_pack(cmph_t *mphf, void *packed_mphf);
+ *  \brief Support the ability to pack a perfect hash function into a preallocated contiguous memory space pointed by packed_mphf.
+ *  \param mphf pointer to the resulting mphf
+ *  \param packed_mphf pointer to the contiguous memory area used to store the resulting mphf. The size of packed_mphf must be at least cmph_packed_size() 
+ */
+void chd_pack(cmph_t *mphf, void *packed_mphf);
+
+/** \fn cmph_uint32 chd_packed_size(cmph_t *mphf);
+ *  \brief Return the amount of space needed to pack mphf.
+ *  \param mphf pointer to a mphf
+ *  \return the size of the packed function or zero for failures
+ */ 
+cmph_uint32 chd_packed_size(cmph_t *mphf);
+
+/** cmph_uint32 chd_search(void *packed_mphf, const char *key, cmph_uint32 keylen);
+ *  \brief Use the packed mphf to do a search. 
+ *  \param  packed_mphf pointer to the packed mphf
+ *  \param key key to be hashed
+ *  \param keylen key legth in bytes
+ *  \return The mphf value
+ */
+cmph_uint32 chd_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen);
+
+#endif
diff --git a/girepository/cmph/chd_ph.c b/girepository/cmph/chd_ph.c
new file mode 100644
index 0000000..b34415b
--- /dev/null
+++ b/girepository/cmph/chd_ph.c
@@ -0,0 +1,988 @@
+#include<stdio.h>
+#include<stdlib.h>
+#include<string.h>
+#include<math.h>
+#include<time.h>
+#include<assert.h>
+#include<limits.h>
+
+#include "cmph_structs.h"
+#include "chd_structs_ph.h"
+#include "chd_ph.h"
+#include"miller_rabin.h"
+#include"bitbool.h"
+
+
+//#define DEBUG
+#include "debug.h"
+
+// NO_ELEMENT is equivalent to null pointer
+#ifndef NO_ELEMENT
+#define NO_ELEMENT UINT_MAX
+#endif
+
+// struct used to represent items at mapping, ordering and searching phases
+struct _chd_ph_item_t
+{
+	cmph_uint32 f;
+	cmph_uint32 h;
+};
+typedef struct _chd_ph_item_t chd_ph_item_t;
+
+// struct to represent the items at mapping phase only. 
+struct _chd_ph_map_item_t
+{
+	cmph_uint32 f;
+	cmph_uint32 h;
+	cmph_uint32 bucket_num;
+};
+typedef struct _chd_ph_map_item_t chd_ph_map_item_t;
+
+// struct to represent a bucket
+struct _chd_ph_bucket_t
+{
+	cmph_uint32 items_list; // offset
+	union
+	{
+		cmph_uint32 size;
+		cmph_uint32 bucket_id;
+	};
+};
+
+typedef struct _chd_ph_bucket_t chd_ph_bucket_t;
+
+struct _chd_ph_sorted_list_t
+{
+	cmph_uint32 buckets_list;
+	cmph_uint32 size;
+};
+
+typedef struct _chd_ph_sorted_list_t chd_ph_sorted_list_t;
+
+
+static inline chd_ph_bucket_t * chd_ph_bucket_new(cmph_uint32 nbuckets);
+static inline void chd_ph_bucket_clean(chd_ph_bucket_t * buckets, cmph_uint32 nbuckets);
+static inline void chd_ph_bucket_destroy(chd_ph_bucket_t * buckets);
+
+chd_ph_bucket_t * chd_ph_bucket_new(cmph_uint32 nbuckets)
+{
+    chd_ph_bucket_t * buckets = (chd_ph_bucket_t *) calloc(nbuckets, sizeof(chd_ph_bucket_t));
+    return buckets;
+}
+
+void chd_ph_bucket_clean(chd_ph_bucket_t * buckets, cmph_uint32 nbuckets)
+{
+	register cmph_uint32 i = 0;
+	assert(buckets);
+	for(i = 0; i < nbuckets; i++)
+		buckets[i].size = 0;
+}
+cmph_uint8 chd_ph_bucket_insert(chd_ph_bucket_t * buckets,chd_ph_map_item_t * map_items, chd_ph_item_t * items,
+				cmph_uint32 nbuckets,cmph_uint32 item_idx)
+{
+	register cmph_uint32 i = 0;
+	register chd_ph_item_t * tmp_item;
+	register chd_ph_map_item_t * tmp_map_item = map_items + item_idx;
+	register chd_ph_bucket_t * bucket = buckets + tmp_map_item->bucket_num;
+	tmp_item = items + bucket->items_list;
+	
+	for(i = 0; i < bucket->size; i++)
+	{
+		if(tmp_item->f == tmp_map_item->f && tmp_item->h == tmp_map_item->h)
+		{
+			DEBUGP("Item not added\n");
+			return 0;
+		};
+		tmp_item++;
+	};
+	tmp_item->f = tmp_map_item->f;
+	tmp_item->h = tmp_map_item->h;
+	bucket->size++;
+	return 1;
+};
+void chd_ph_bucket_destroy(chd_ph_bucket_t * buckets)
+{
+    free(buckets);
+}
+
+static inline cmph_uint8 chd_ph_mapping(cmph_config_t *mph, chd_ph_bucket_t * buckets, chd_ph_item_t * items, 
+					cmph_uint32 *max_bucket_size);
+
+static chd_ph_sorted_list_t * chd_ph_ordering(chd_ph_bucket_t ** _buckets,chd_ph_item_t ** items,
+				cmph_uint32 nbuckets,cmph_uint32 nitems, cmph_uint32 max_bucket_size);
+
+static cmph_uint8 chd_ph_searching(chd_ph_config_data_t *chd_ph, chd_ph_bucket_t *buckets, chd_ph_item_t *items ,
+	cmph_uint32 max_bucket_size, chd_ph_sorted_list_t *sorted_lists, cmph_uint32 max_probes, cmph_uint32 * disp_table);
+
+static inline double chd_ph_space_lower_bound(cmph_uint32 _n, cmph_uint32 _r)
+{
+	double r = _r, n = _n;
+	return (1 + (r/n - 1.0 + 1.0/(2.0*n))*log(1 - n/r))/log(2);
+};
+
+/* computes the entropy of non empty buckets.*/
+static inline double chd_ph_get_entropy(cmph_uint32 * disp_table, cmph_uint32 n, cmph_uint32 max_probes)
+{
+	register cmph_uint32 * probe_counts = (cmph_uint32 *) calloc(max_probes, sizeof(cmph_uint32));
+	register cmph_uint32 i;
+	register double entropy = 0;
+
+	for(i = 0; i < n; i++)
+	{
+		probe_counts[disp_table[i]]++;
+	};
+	
+	for(i = 0; i < max_probes; i++)
+	{
+		if(probe_counts[i] > 0)
+			entropy -= probe_counts[i]*log((double)probe_counts[i]/(double)n)/log(2);
+	};
+	free(probe_counts);
+	return entropy;
+};
+
+chd_ph_config_data_t *chd_ph_config_new()
+{
+	chd_ph_config_data_t *chd_ph;
+	chd_ph = (chd_ph_config_data_t *)malloc(sizeof(chd_ph_config_data_t));
+	assert(chd_ph);
+	memset(chd_ph, 0, sizeof(chd_ph_config_data_t));
+	
+	chd_ph->hashfunc = CMPH_HASH_JENKINS;
+	chd_ph->cs = NULL;
+	chd_ph->nbuckets = 0;
+	chd_ph->n = 0;
+	chd_ph->hl = NULL;
+
+	chd_ph->m = 0;
+	chd_ph->use_h = 1;
+	chd_ph->keys_per_bin = 1;
+	chd_ph->keys_per_bucket = 4;
+	chd_ph->occup_table = 0;
+	
+	return chd_ph;
+}
+
+void chd_ph_config_destroy(cmph_config_t *mph)
+{
+	chd_ph_config_data_t *data = (chd_ph_config_data_t *) mph->data;
+	DEBUGP("Destroying algorithm dependent data\n");
+	if(data->occup_table)
+	{
+		free(data->occup_table);
+		data->occup_table = NULL;
+	}
+	free(data);
+}
+
+
+void chd_ph_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs)
+{
+	chd_ph_config_data_t *chd_ph = (chd_ph_config_data_t *)mph->data;
+	CMPH_HASH *hashptr = hashfuncs;
+	cmph_uint32 i = 0;
+	while(*hashptr != CMPH_HASH_COUNT)
+	{
+		if (i >= 1) break; //chd_ph only uses one linear hash function
+		chd_ph->hashfunc = *hashptr;	
+		++i, ++hashptr;
+	}
+}
+
+
+void chd_ph_config_set_b(cmph_config_t *mph, cmph_uint32 keys_per_bucket)
+{
+	assert(mph);
+	chd_ph_config_data_t *chd_ph = (chd_ph_config_data_t *)mph->data;
+	if(keys_per_bucket < 1 || keys_per_bucket >= 15)
+	{
+	    keys_per_bucket = 4;
+	}
+	chd_ph->keys_per_bucket = keys_per_bucket;
+}
+
+
+void chd_ph_config_set_keys_per_bin(cmph_config_t *mph, cmph_uint32 keys_per_bin)
+{
+	assert(mph);
+	chd_ph_config_data_t *chd_ph = (chd_ph_config_data_t *)mph->data;
+	if(keys_per_bin <= 1 || keys_per_bin >= 128)
+	{
+	    keys_per_bin = 1;
+	}
+	chd_ph->keys_per_bin = keys_per_bin;
+}
+
+cmph_uint8 chd_ph_mapping(cmph_config_t *mph, chd_ph_bucket_t * buckets, chd_ph_item_t * items, cmph_uint32 *max_bucket_size)
+{
+	register cmph_uint32 i = 0, g = 0;
+	cmph_uint32 hl[3];
+	chd_ph_config_data_t *chd_ph = (chd_ph_config_data_t *)mph->data;
+	char * key = NULL;
+	cmph_uint32 keylen = 0;
+	chd_ph_map_item_t * map_item;
+	chd_ph_map_item_t * map_items = malloc(chd_ph->m*sizeof(chd_ph_map_item_t));
+	register cmph_uint32 mapping_iterations = 1000;
+	*max_bucket_size = 0;
+	while(1)
+	{
+		mapping_iterations--;
+		if (chd_ph->hl) hash_state_destroy(chd_ph->hl);
+		chd_ph->hl = hash_state_new(chd_ph->hashfunc, chd_ph->m); 
+
+		chd_ph_bucket_clean(buckets, chd_ph->nbuckets);
+
+		mph->key_source->rewind(mph->key_source->data);  
+
+		for(i = 0; i < chd_ph->m; i++)
+		{
+			mph->key_source->read(mph->key_source->data, &key, &keylen);		
+			hash_vector(chd_ph->hl, key, keylen, hl);
+			
+			map_item = (map_items + i);
+
+			g = hl[0] % chd_ph->nbuckets;
+			map_item->f = hl[1] % chd_ph->n;
+			map_item->h = hl[2] % (chd_ph->n - 1) + 1;
+			map_item->bucket_num=g;
+			mph->key_source->dispose(mph->key_source->data, key, keylen);		
+// 			if(buckets[g].size == (chd_ph->keys_per_bucket << 2))
+// 			{
+// 				DEBUGP("BUCKET = %u -- SIZE = %u -- MAXIMUM SIZE = %u\n", g, buckets[g].size, (chd_ph->keys_per_bucket << 2));
+// 				goto error;
+// 			}
+			buckets[g].size++;
+			if(buckets[g].size > *max_bucket_size)
+			{
+				  *max_bucket_size = buckets[g].size;
+			}
+		}
+		buckets[0].items_list = 0;
+		for(i = 1; i < chd_ph->nbuckets; i++)
+		{
+			buckets[i].items_list = buckets[i-1].items_list + buckets[i - 1].size;
+			buckets[i - 1].size = 0;
+		};
+		buckets[i - 1].size = 0;
+		for(i = 0; i < chd_ph->m; i++)
+		{
+			map_item = (map_items + i);
+			if(!chd_ph_bucket_insert(buckets, map_items, items, chd_ph->nbuckets, i))
+				break;
+		}
+		if(i == chd_ph->m)
+		{
+			free(map_items);
+			return 1; // SUCCESS
+		}
+		
+		if(mapping_iterations == 0)
+		{
+		      goto error;
+		}
+	}
+error:
+	free(map_items);
+	hash_state_destroy(chd_ph->hl);
+	chd_ph->hl = NULL;
+	return 0; // FAILURE
+}
+
+chd_ph_sorted_list_t * chd_ph_ordering(chd_ph_bucket_t ** _buckets, chd_ph_item_t ** _items,
+	cmph_uint32 nbuckets, cmph_uint32 nitems, cmph_uint32 max_bucket_size)
+{
+	chd_ph_sorted_list_t * sorted_lists = (chd_ph_sorted_list_t *) calloc(max_bucket_size + 1, sizeof(chd_ph_sorted_list_t));
+	
+	chd_ph_bucket_t * input_buckets = (*_buckets);
+	chd_ph_bucket_t * output_buckets;
+	chd_ph_item_t * input_items = (*_items);
+	chd_ph_item_t * output_items;
+	register cmph_uint32 i, j, bucket_size, position, position2;
+// 	cmph_uint32 non_empty_buckets;
+	DEBUGP("MAX BUCKET SIZE = %u\n", max_bucket_size);
+	// Determine size of each list of buckets
+	for(i = 0; i < nbuckets; i++)
+	{
+		bucket_size = input_buckets[i].size;
+		if(bucket_size == 0)
+			continue;
+		sorted_lists[bucket_size].size++;
+	};
+	sorted_lists[1].buckets_list = 0;
+	// Determine final position of list of buckets into the contiguous array that will store all the buckets
+	for(i = 2; i <= max_bucket_size; i++)
+	{
+		sorted_lists[i].buckets_list = sorted_lists[i-1].buckets_list + sorted_lists[i-1].size;
+		sorted_lists[i-1].size = 0;
+	};
+	sorted_lists[i-1].size = 0;
+	// Store the buckets in a new array which is sorted by bucket sizes
+	output_buckets = calloc(nbuckets, sizeof(chd_ph_bucket_t)); // everything is initialized with zero
+//  	non_empty_buckets = nbuckets;
+	
+	for(i = 0; i < nbuckets; i++)
+	{
+		bucket_size = input_buckets[i].size;
+		if(bucket_size == 0)
+		{
+// 			non_empty_buckets--;
+			continue;
+		};
+		position = sorted_lists[bucket_size].buckets_list + sorted_lists[bucket_size].size;
+		output_buckets[position].bucket_id = i;
+		output_buckets[position].items_list = input_buckets[i].items_list;
+		sorted_lists[bucket_size].size++;
+	};
+/*	for(i = non_empty_buckets; i < nbuckets; i++)
+		output_buckets[i].size=0;*/
+	// Return the buckets sorted in new order and free the old buckets sorted in old order
+	free(input_buckets);
+	(*_buckets) = output_buckets;
+	
+	
+	// Store the items according to the new order of buckets.
+	output_items = (chd_ph_item_t*)calloc(nitems, sizeof(chd_ph_item_t));
+	position = 0;
+	i = 0;
+	for(bucket_size = 1; bucket_size <= max_bucket_size; bucket_size++)
+	{
+		for(i = sorted_lists[bucket_size].buckets_list; i < sorted_lists[bucket_size].size + sorted_lists[bucket_size].buckets_list; i++)
+		{
+			position2 = output_buckets[i].items_list;
+			output_buckets[i].items_list = position;
+			for(j = 0; j < bucket_size; j++)
+			{
+				output_items[position].f = input_items[position2].f;
+				output_items[position].h = input_items[position2].h;
+				position++;
+				position2++;
+			};
+		};
+	};
+	//Return the items sorted in new order and free the old items sorted in old order
+	free(input_items);
+	(*_items) = output_items;
+	return sorted_lists;
+};
+
+static inline cmph_uint8 place_bucket_probe(chd_ph_config_data_t *chd_ph, chd_ph_bucket_t *buckets,
+					    chd_ph_item_t *items, cmph_uint32 probe0_num, cmph_uint32 probe1_num,
+					    cmph_uint32 bucket_num, cmph_uint32 size)
+{
+	register cmph_uint32 i;
+	register chd_ph_item_t * item;
+	register cmph_uint32 position;
+
+	item = items + buckets[bucket_num].items_list;
+	// try place bucket with probe_num
+	if(chd_ph->keys_per_bin > 1)
+	{
+		for(i = 0; i < size; i++) // placement
+		{
+			position = (cmph_uint32)((item->f + ((cmph_uint64)item->h)*probe0_num + probe1_num) % chd_ph->n);
+			if(chd_ph->occup_table[position] >= chd_ph->keys_per_bin)
+			{
+				break;
+			}
+			(chd_ph->occup_table[position])++;
+			item++;
+		};
+	} else
+	{
+		for(i = 0; i < size; i++) // placement
+		{
+			position = (cmph_uint32)((item->f + ((cmph_uint64)item->h)*probe0_num + probe1_num) % chd_ph->n);
+			if(GETBIT32(((cmph_uint32 *)chd_ph->occup_table), position))
+			{
+				break;
+			}
+			SETBIT32(((cmph_uint32*)chd_ph->occup_table), position);
+			item++;
+		};
+	};
+	if(i != size) // Undo the placement
+	{
+		item = items + buckets[bucket_num].items_list;
+		if(chd_ph->keys_per_bin > 1)
+		{
+			while(1)
+			{
+				if(i == 0)
+				{
+					break;
+				}
+				position = (cmph_uint32)((item->f + ((cmph_uint64 )item->h) * probe0_num + probe1_num) % chd_ph->n);
+				(chd_ph->occup_table[position])--;
+				item++;
+				i--;
+			};
+		} else
+		{
+			while(1)
+			{
+				if(i == 0)
+				{
+					break;
+				}
+				position = (cmph_uint32)((item->f + ((cmph_uint64 )item->h) * probe0_num + probe1_num) % chd_ph->n);
+				UNSETBIT32(((cmph_uint32*)chd_ph->occup_table), position);
+				
+// 				([position/32]^=(1<<(position%32));
+				item++;
+				i--;
+			};
+		};
+		return 0;
+	} 	
+	return 1;
+};
+
+static inline cmph_uint8 place_bucket(chd_ph_config_data_t *chd_ph, chd_ph_bucket_t *buckets, chd_ph_item_t * items, cmph_uint32 max_probes, 
+                                      cmph_uint32 * disp_table, cmph_uint32 bucket_num, cmph_uint32 size)
+				      
+{
+	register cmph_uint32 probe0_num, probe1_num, probe_num;
+	probe0_num = 0;
+	probe1_num = 0;
+	probe_num = 0;
+	
+	while(1)
+	{
+		if(place_bucket_probe(chd_ph, buckets, items, probe0_num, probe1_num, bucket_num,size))
+		{
+			disp_table[buckets[bucket_num].bucket_id] = probe0_num + probe1_num * chd_ph->n;
+			return 1;
+		}
+		probe0_num++;
+		if(probe0_num >= chd_ph->n)
+		{
+			probe0_num -= chd_ph->n;
+			probe1_num++;
+		};
+		probe_num++;
+		if(probe_num >= max_probes || probe1_num >= chd_ph->n)
+		{
+			return 0;
+		};
+	};
+	return 0;
+};
+
+static inline cmph_uint8 place_buckets1(chd_ph_config_data_t *chd_ph, chd_ph_bucket_t * buckets, chd_ph_item_t *items,
+					cmph_uint32 max_bucket_size, chd_ph_sorted_list_t *sorted_lists, cmph_uint32 max_probes, 
+					cmph_uint32 * disp_table)
+{
+	register cmph_uint32 i = 0;
+	register cmph_uint32 curr_bucket = 0;
+
+	for(i = max_bucket_size; i > 0; i--)
+	{
+		curr_bucket = sorted_lists[i].buckets_list;
+		while(curr_bucket < sorted_lists[i].size + sorted_lists[i].buckets_list)
+		{
+			if(!place_bucket(chd_ph, buckets, items, max_probes, disp_table, curr_bucket, i))
+			{
+				return 0;
+			}
+			curr_bucket++;
+		};
+	};
+	return 1;
+};
+
+static inline cmph_uint8 place_buckets2(chd_ph_config_data_t *chd_ph, chd_ph_bucket_t *buckets, chd_ph_item_t * items, 
+					cmph_uint32 max_bucket_size, chd_ph_sorted_list_t *sorted_lists, cmph_uint32 max_probes, 
+					cmph_uint32 * disp_table)
+{
+	register cmph_uint32 i,j, non_placed_bucket;
+	register cmph_uint32 curr_bucket;
+	register cmph_uint32 probe_num, probe0_num, probe1_num;
+	cmph_uint32 sorted_list_size;
+#ifdef DEBUG
+	cmph_uint32 items_list;
+	cmph_uint32 bucket_id;
+#endif
+	DEBUGP("USING HEURISTIC TO PLACE BUCKETS\n");
+	for(i = max_bucket_size; i > 0; i--)
+	{
+		probe_num = 0;
+		probe0_num = 0;
+		probe1_num = 0;
+		sorted_list_size = sorted_lists[i].size;
+		while(sorted_lists[i].size != 0)
+		{
+			curr_bucket = sorted_lists[i].buckets_list;
+			for(j = 0, non_placed_bucket = 0; j < sorted_lists[i].size; j++)
+			{
+				// if bucket is successfully placed remove it from list
+				if(place_bucket_probe(chd_ph, buckets, items, probe0_num, probe1_num, curr_bucket, i))
+				{	
+					disp_table[buckets[curr_bucket].bucket_id] = probe0_num + probe1_num * chd_ph->n;
+// 					DEBUGP("BUCKET %u PLACED --- DISPLACEMENT = %u\n", curr_bucket, disp_table[curr_bucket]);
+				} 
+				else
+				{
+// 					DEBUGP("BUCKET %u NOT PLACED\n", curr_bucket);
+#ifdef DEBUG
+					items_list = buckets[non_placed_bucket + sorted_lists[i].buckets_list].items_list;
+					bucket_id = buckets[non_placed_bucket + sorted_lists[i].buckets_list].bucket_id;
+#endif
+					buckets[non_placed_bucket + sorted_lists[i].buckets_list].items_list = buckets[curr_bucket].items_list;
+					buckets[non_placed_bucket + sorted_lists[i].buckets_list].bucket_id = buckets[curr_bucket].bucket_id;
+#ifdef DEBUG		
+					buckets[curr_bucket].items_list=items_list;
+					buckets[curr_bucket].bucket_id=bucket_id;
+#endif
+					non_placed_bucket++;
+				}
+				curr_bucket++;
+			};
+			sorted_lists[i].size = non_placed_bucket;
+			probe0_num++;
+			if(probe0_num >= chd_ph->n)
+			{
+				probe0_num -= chd_ph->n;
+				probe1_num++;
+			};
+			probe_num++;
+			if(probe_num >= max_probes || probe1_num >= chd_ph->n)
+			{
+				sorted_lists[i].size = sorted_list_size;
+				return 0;
+			};
+		};
+		sorted_lists[i].size = sorted_list_size;
+	};
+	return 1;
+};
+
+cmph_uint8 chd_ph_searching(chd_ph_config_data_t *chd_ph, chd_ph_bucket_t *buckets, chd_ph_item_t *items ,
+			    cmph_uint32 max_bucket_size, chd_ph_sorted_list_t *sorted_lists, cmph_uint32 max_probes, 
+			    cmph_uint32 * disp_table)
+{
+	if(chd_ph->use_h)
+	{
+		return place_buckets2(chd_ph, buckets, items, max_bucket_size, sorted_lists, max_probes, disp_table);
+	}
+	else
+	{
+		return place_buckets1(chd_ph, buckets, items, max_bucket_size, sorted_lists, max_probes, disp_table);
+	}
+
+}
+
+static inline cmph_uint8 chd_ph_check_bin_hashing(chd_ph_config_data_t *chd_ph, chd_ph_bucket_t *buckets, chd_ph_item_t *items,
+                                                  cmph_uint32 * disp_table, chd_ph_sorted_list_t * sorted_lists,cmph_uint32 max_bucket_size)
+{
+	register cmph_uint32 bucket_size, i, j;
+	register cmph_uint32 position, probe0_num, probe1_num;
+	register cmph_uint32 m = 0;
+	register chd_ph_item_t * item;
+	if(chd_ph->keys_per_bin > 1)
+		memset(chd_ph->occup_table, 0, chd_ph->n);
+	else
+		memset(chd_ph->occup_table, 0, ((chd_ph->n + 31)/32) * sizeof(cmph_uint32));
+		
+	for(bucket_size = 1; bucket_size <= max_bucket_size; bucket_size++)
+		for(i = sorted_lists[bucket_size].buckets_list; i < sorted_lists[bucket_size].size +
+				sorted_lists[bucket_size].buckets_list; i++)
+		{
+			j = bucket_size;
+			item = items + buckets[i].items_list;
+			probe0_num = disp_table[buckets[i].bucket_id] % chd_ph->n;
+			probe1_num = disp_table[buckets[i].bucket_id] / chd_ph->n;
+			for(; j > 0; j--)
+			{
+				m++;
+				position = (cmph_uint32)((item->f + ((cmph_uint64 )item->h) * probe0_num + probe1_num) % chd_ph->n);
+				if(chd_ph->keys_per_bin > 1)
+				{
+					if(chd_ph->occup_table[position] >= chd_ph->keys_per_bin)
+					{
+						return 0;
+					}
+					(chd_ph->occup_table[position])++;
+				} 
+				else
+				{
+					if(GETBIT32(((cmph_uint32*)chd_ph->occup_table), position))
+					{
+						return 0;
+					}
+					SETBIT32(((cmph_uint32*)chd_ph->occup_table), position);
+				};
+				item++;
+			};
+		};
+	DEBUGP("We were able to place m = %u keys\n", m);
+	return 1;
+};
+
+
+cmph_t *chd_ph_new(cmph_config_t *mph, double c)
+{
+	cmph_t *mphf = NULL;
+	chd_ph_data_t *chd_phf = NULL;
+	chd_ph_config_data_t *chd_ph = (chd_ph_config_data_t *)mph->data;
+	
+	register double load_factor = c;
+	register cmph_uint8 searching_success = 0;
+	register cmph_uint32 max_probes = 1 << 20; // default value for max_probes
+	register cmph_uint32 iterations = 100;
+	chd_ph_bucket_t * buckets = NULL;
+	chd_ph_item_t * items = NULL;
+	register cmph_uint8 failure = 0;
+	cmph_uint32 max_bucket_size = 0;
+	chd_ph_sorted_list_t * sorted_lists = NULL;
+	cmph_uint32 * disp_table = NULL;
+	register double space_lower_bound = 0;
+	#ifdef CMPH_TIMING
+	double construction_time_begin = 0.0;
+	double construction_time = 0.0;
+	ELAPSED_TIME_IN_SECONDS(&construction_time_begin);
+	#endif
+
+
+	chd_ph->m = mph->key_source->nkeys;
+	DEBUGP("m = %u\n", chd_ph->m);
+	
+	chd_ph->nbuckets = (cmph_uint32)(chd_ph->m/chd_ph->keys_per_bucket) + 1;
+	DEBUGP("nbuckets = %u\n", chd_ph->nbuckets);
+	
+	if(load_factor < 0.5 )
+	{
+		load_factor = 0.5;
+	}
+	
+	if(load_factor >= 0.99)
+	{
+		load_factor = 0.99;
+	}
+	
+	DEBUGP("load_factor = %.3f\n", load_factor);
+	
+	chd_ph->n = (cmph_uint32)(chd_ph->m/(chd_ph->keys_per_bin * load_factor)) + 1;
+	
+	//Round the number of bins to the prime immediately above
+	if(chd_ph->n % 2 == 0) chd_ph->n++;
+	for(;;)
+	{
+		if(check_primality(chd_ph->n) == 1)
+			break;
+		chd_ph->n += 2; // just odd numbers can be primes for n > 2
+		
+	};
+	
+	DEBUGP("n = %u \n", chd_ph->n);
+	if(chd_ph->keys_per_bin == 1)
+	{
+		space_lower_bound = chd_ph_space_lower_bound(chd_ph->m, chd_ph->n);
+	}
+	
+	if(mph->verbosity)
+	{
+		fprintf(stderr, "space lower bound is %.3f bits per key\n", space_lower_bound);
+	}
+
+       	// We allocate the working tables
+	buckets = chd_ph_bucket_new(chd_ph->nbuckets); 
+	items   = (chd_ph_item_t *) calloc(chd_ph->m, sizeof(chd_ph_item_t));
+
+	max_probes = (cmph_uint32)(((log(chd_ph->m)/log(2))/20) * max_probes);
+	
+	if(chd_ph->keys_per_bin == 1)
+		chd_ph->occup_table = (cmph_uint8 *) calloc(((chd_ph->n + 31)/32), sizeof(cmph_uint32));
+	else
+		chd_ph->occup_table = (cmph_uint8 *) calloc(chd_ph->n, sizeof(cmph_uint8));
+		
+	disp_table = (cmph_uint32 *) calloc(chd_ph->nbuckets, sizeof(cmph_uint32));
+// 	
+// 	init_genrand(time(0));
+	
+	while(1)
+	{
+		iterations --;
+		if (mph->verbosity)
+		{
+			fprintf(stderr, "Starting mapping step for mph creation of %u keys with %u bins\n", chd_ph->m, chd_ph->n);
+		}
+		
+		if(!chd_ph_mapping(mph, buckets, items, &max_bucket_size))
+		{
+			if (mph->verbosity)
+			{
+				fprintf(stderr, "Failure in mapping step\n");		
+			}
+			failure = 1;
+			goto cleanup;
+		}
+
+		if (mph->verbosity)
+		{
+			fprintf(stderr, "Starting ordering step\n");
+		}
+		if(sorted_lists)
+		{
+			free(sorted_lists);
+		}
+
+        	sorted_lists = chd_ph_ordering(&buckets, &items, chd_ph->nbuckets, chd_ph->m, max_bucket_size);
+		
+		if (mph->verbosity)
+		{
+			fprintf(stderr, "Starting searching step\n");
+		}
+		
+		searching_success = chd_ph_searching(chd_ph, buckets, items, max_bucket_size, sorted_lists, max_probes, disp_table);
+		if(searching_success) break;
+		
+		// reset occup_table
+		if(chd_ph->keys_per_bin > 1)
+			memset(chd_ph->occup_table, 0, chd_ph->n);
+		else
+			memset(chd_ph->occup_table, 0, ((chd_ph->n + 31)/32) * sizeof(cmph_uint32));
+		if(iterations == 0)
+		{
+			// Cleanup memory
+			if (mph->verbosity)
+			{
+				fprintf(stderr, "Failure because the max trials was exceeded\n");
+			}
+			failure = 1;
+			goto cleanup;
+		};
+	}
+
+	#ifdef DEBUG
+	{
+		if(!chd_ph_check_bin_hashing(chd_ph, buckets, items, disp_table,sorted_lists,max_bucket_size))
+		{
+		
+			DEBUGP("Error for bin packing generation");
+			failure = 1;
+			goto cleanup;
+		}
+	}
+	#endif
+	
+	if (mph->verbosity)
+	{
+		fprintf(stderr, "Starting compressing step\n");
+	}
+	
+	if(chd_ph->cs)
+	{
+		free(chd_ph->cs);
+	}
+	chd_ph->cs = (compressed_seq_t *) calloc(1, sizeof(compressed_seq_t));
+	compressed_seq_init(chd_ph->cs);
+	compressed_seq_generate(chd_ph->cs, disp_table, chd_ph->nbuckets);
+	
+	#ifdef CMPH_TIMING
+	ELAPSED_TIME_IN_SECONDS(&construction_time);
+	register double entropy = chd_ph_get_entropy(disp_table, chd_ph->nbuckets, max_probes);
+	DEBUGP("Entropy = %.4f\n", entropy/chd_ph->m);
+	#endif
+
+cleanup:
+	chd_ph_bucket_destroy(buckets); 
+	free(items);
+	free(sorted_lists);
+	free(disp_table);
+	if(failure) 
+	{
+		if(chd_ph->hl)
+		{
+			hash_state_destroy(chd_ph->hl);
+		}
+		chd_ph->hl = NULL;
+		return NULL;
+	}
+
+	mphf = (cmph_t *)malloc(sizeof(cmph_t));
+	mphf->algo = mph->algo;
+	chd_phf = (chd_ph_data_t *)malloc(sizeof(chd_ph_data_t));
+	
+	chd_phf->cs = chd_ph->cs;
+	chd_ph->cs = NULL; //transfer memory ownership
+	chd_phf->hl = chd_ph->hl;
+	chd_ph->hl = NULL; //transfer memory ownership
+	chd_phf->n = chd_ph->n;
+	chd_phf->nbuckets = chd_ph->nbuckets;
+	
+	mphf->data = chd_phf;
+	mphf->size = chd_ph->n;
+
+	DEBUGP("Successfully generated minimal perfect hash\n");
+	if (mph->verbosity)
+	{
+		fprintf(stderr, "Successfully generated minimal perfect hash function\n");
+	}
+	
+	#ifdef CMPH_TIMING	
+	register cmph_uint32 space_usage = chd_ph_packed_size(mphf)*8;
+	construction_time = construction_time - construction_time_begin;
+	fprintf(stdout, "%u\t%.2f\t%u\t%.4f\t%.4f\t%.4f\t%.4f\n", chd_ph->m, load_factor, chd_ph->keys_per_bucket, construction_time, space_usage/(double)chd_ph->m, space_lower_bound, entropy/chd_ph->m);
+	#endif	
+
+	return mphf;
+}
+
+
+
+void chd_ph_load(FILE *fd, cmph_t *mphf)
+{
+	char *buf = NULL;
+	cmph_uint32 buflen;
+	register size_t nbytes;
+	chd_ph_data_t *chd_ph = (chd_ph_data_t *)malloc(sizeof(chd_ph_data_t));
+
+	DEBUGP("Loading chd_ph mphf\n");
+	mphf->data = chd_ph;
+
+	nbytes = fread(&buflen, sizeof(cmph_uint32), (size_t)1, fd);
+	DEBUGP("Hash state has %u bytes\n", buflen);
+	buf = (char *)malloc((size_t)buflen);
+	nbytes = fread(buf, (size_t)buflen, (size_t)1, fd);
+	chd_ph->hl = hash_state_load(buf, buflen);
+	free(buf);
+	
+	nbytes = fread(&buflen, sizeof(cmph_uint32), (size_t)1, fd);
+	DEBUGP("Compressed sequence structure has %u bytes\n", buflen);
+	buf = (char *)malloc((size_t)buflen);
+	nbytes = fread(buf, (size_t)buflen, (size_t)1, fd);
+	chd_ph->cs = (compressed_seq_t *) calloc(1, sizeof(compressed_seq_t)); 
+	compressed_seq_load(chd_ph->cs, buf, buflen);
+	free(buf);
+	
+	// loading n and nbuckets
+	DEBUGP("Reading n and nbuckets\n");
+	nbytes = fread(&(chd_ph->n), sizeof(cmph_uint32), (size_t)1, fd);	
+	nbytes = fread(&(chd_ph->nbuckets), sizeof(cmph_uint32), (size_t)1, fd);	
+}
+
+int chd_ph_dump(cmph_t *mphf, FILE *fd)
+{
+	char *buf = NULL;
+	cmph_uint32 buflen;
+	register size_t nbytes;
+	chd_ph_data_t *data = (chd_ph_data_t *)mphf->data;
+	
+	__cmph_dump(mphf, fd);
+
+	hash_state_dump(data->hl, &buf, &buflen);
+	DEBUGP("Dumping hash state with %u bytes to disk\n", buflen);
+	nbytes = fwrite(&buflen, sizeof(cmph_uint32), (size_t)1, fd);
+	nbytes = fwrite(buf, (size_t)buflen, (size_t)1, fd);
+	free(buf);
+
+	compressed_seq_dump(data->cs, &buf, &buflen);
+	DEBUGP("Dumping compressed sequence structure with %u bytes to disk\n", buflen);
+	nbytes = fwrite(&buflen, sizeof(cmph_uint32), (size_t)1, fd);
+	nbytes = fwrite(buf, (size_t)buflen, (size_t)1, fd);
+	free(buf);
+
+	// dumping n and nbuckets
+	nbytes = fwrite(&(data->n), sizeof(cmph_uint32), (size_t)1, fd);
+	nbytes = fwrite(&(data->nbuckets), sizeof(cmph_uint32), (size_t)1, fd);
+	return 1;
+}
+
+void chd_ph_destroy(cmph_t *mphf)
+{
+	chd_ph_data_t *data = (chd_ph_data_t *)mphf->data;
+	compressed_seq_destroy(data->cs);
+	free(data->cs);
+	hash_state_destroy(data->hl);
+	free(data);
+	free(mphf);
+
+}
+
+cmph_uint32 chd_ph_search(cmph_t *mphf, const char *key, cmph_uint32 keylen)
+{
+	register chd_ph_data_t * chd_ph = mphf->data;
+	cmph_uint32 hl[3];
+	register cmph_uint32 disp,position;
+	register cmph_uint32 probe0_num,probe1_num;
+	register cmph_uint32 f,g,h;
+	hash_vector(chd_ph->hl, key, keylen, hl);	
+	g = hl[0] % chd_ph->nbuckets;
+	f = hl[1] % chd_ph->n;
+	h = hl[2] % (chd_ph->n-1) + 1;
+	
+	disp = compressed_seq_query(chd_ph->cs, g);
+	probe0_num = disp % chd_ph->n;
+	probe1_num = disp/chd_ph->n;
+	position = (cmph_uint32)((f + ((cmph_uint64 )h)*probe0_num + probe1_num) % chd_ph->n);
+	return position;
+}
+
+void chd_ph_pack(cmph_t *mphf, void *packed_mphf)
+{
+	chd_ph_data_t *data = (chd_ph_data_t *)mphf->data;
+	cmph_uint8 * ptr = packed_mphf;
+
+	// packing hl type
+	CMPH_HASH hl_type = hash_get_type(data->hl);
+	*((cmph_uint32 *) ptr) = hl_type;
+	ptr += sizeof(cmph_uint32);
+
+	// packing hl
+	hash_state_pack(data->hl, ptr);
+	ptr += hash_state_packed_size(hl_type);
+
+	// packing n
+	*((cmph_uint32 *) ptr) = data->n;
+	ptr += sizeof(data->n);
+
+	// packing nbuckets
+	*((cmph_uint32 *) ptr) = data->nbuckets;
+	ptr += sizeof(data->nbuckets);
+
+	// packing cs
+	compressed_seq_pack(data->cs, ptr);
+	//ptr += compressed_seq_packed_size(data->cs);
+
+}
+
+cmph_uint32 chd_ph_packed_size(cmph_t *mphf)
+{
+	register chd_ph_data_t *data = (chd_ph_data_t *)mphf->data;
+	register CMPH_HASH hl_type = hash_get_type(data->hl); 
+	register cmph_uint32 hash_state_pack_size =  hash_state_packed_size(hl_type);
+	register cmph_uint32 cs_pack_size = compressed_seq_packed_size(data->cs);
+	
+	return (cmph_uint32)(sizeof(CMPH_ALGO) + hash_state_pack_size + cs_pack_size + 3*sizeof(cmph_uint32));
+
+}
+
+cmph_uint32 chd_ph_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen)
+{
+	register CMPH_HASH hl_type  = *(cmph_uint32 *)packed_mphf;
+	register cmph_uint8 *hl_ptr = (cmph_uint8 *)(packed_mphf) + 4;
+	
+	register cmph_uint32 * ptr = (cmph_uint32 *)(hl_ptr + hash_state_packed_size(hl_type));
+	register cmph_uint32 n = *ptr++;
+	register cmph_uint32 nbuckets = *ptr++;
+	cmph_uint32 hl[3];
+		
+	register cmph_uint32 disp,position;
+	register cmph_uint32 probe0_num,probe1_num;
+	register cmph_uint32 f,g,h;
+	
+	hash_vector_packed(hl_ptr, hl_type, key, keylen, hl);
+
+	g = hl[0] % nbuckets;
+	f = hl[1] % n;
+	h = hl[2] % (n-1) + 1;
+	
+	disp = compressed_seq_query_packed(ptr, g);
+	probe0_num = disp % n;
+	probe1_num = disp/n;
+	position = (cmph_uint32)((f + ((cmph_uint64 )h)*probe0_num + probe1_num) % n);
+	return position;
+}
+
+
+
diff --git a/girepository/cmph/chd_ph.h b/girepository/cmph/chd_ph.h
new file mode 100644
index 0000000..d2bdb02
--- /dev/null
+++ b/girepository/cmph/chd_ph.h
@@ -0,0 +1,59 @@
+#ifndef _CMPH_CHD_PH_H__
+#define _CMPH_CHD_PH_H__
+
+#include "cmph.h"
+
+typedef struct __chd_ph_data_t chd_ph_data_t;
+typedef struct __chd_ph_config_data_t chd_ph_config_data_t;
+
+/* Config API */
+chd_ph_config_data_t *chd_ph_config_new();
+void chd_ph_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs);
+
+/** \fn void chd_ph_config_set_keys_per_bin(cmph_config_t *mph, cmph_uint32 keys_per_bin);
+ *  \brief Allows to set the number of keys per bin.
+ *  \param mph pointer to the configuration structure
+ *  \param keys_per_bin value for the number of keys per bin 
+ */
+void chd_ph_config_set_keys_per_bin(cmph_config_t *mph, cmph_uint32 keys_per_bin);
+
+/** \fn void chd_ph_config_set_b(cmph_config_t *mph, cmph_uint32 keys_per_bucket);
+ *  \brief Allows to set the number of keys per bucket.
+ *  \param mph pointer to the configuration structure
+ *  \param keys_per_bucket value for the number of keys per bucket 
+ */
+void chd_ph_config_set_b(cmph_config_t *mph, cmph_uint32 keys_per_bucket);
+void chd_ph_config_destroy(cmph_config_t *mph);
+
+
+/* Chd algorithm API */
+cmph_t *chd_ph_new(cmph_config_t *mph, double c);
+void chd_ph_load(FILE *fd, cmph_t *mphf);
+int chd_ph_dump(cmph_t *mphf, FILE *fd);
+void chd_ph_destroy(cmph_t *mphf);
+cmph_uint32 chd_ph_search(cmph_t *mphf, const char *key, cmph_uint32 keylen);
+
+/** \fn void chd_ph_pack(cmph_t *mphf, void *packed_mphf);
+ *  \brief Support the ability to pack a perfect hash function into a preallocated contiguous memory space pointed by packed_mphf.
+ *  \param mphf pointer to the resulting mphf
+ *  \param packed_mphf pointer to the contiguous memory area used to store the resulting mphf. The size of packed_mphf must be at least cmph_packed_size() 
+ */
+void chd_ph_pack(cmph_t *mphf, void *packed_mphf);
+
+/** \fn cmph_uint32 chd_ph_packed_size(cmph_t *mphf);
+ *  \brief Return the amount of space needed to pack mphf.
+ *  \param mphf pointer to a mphf
+ *  \return the size of the packed function or zero for failures
+ */ 
+cmph_uint32 chd_ph_packed_size(cmph_t *mphf);
+
+/** cmph_uint32 chd_ph_search(void *packed_mphf, const char *key, cmph_uint32 keylen);
+ *  \brief Use the packed mphf to do a search. 
+ *  \param  packed_mphf pointer to the packed mphf
+ *  \param key key to be hashed
+ *  \param keylen key legth in bytes
+ *  \return The mphf value
+ */
+cmph_uint32 chd_ph_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen);
+
+#endif
diff --git a/girepository/cmph/chd_structs.h b/girepository/cmph/chd_structs.h
new file mode 100644
index 0000000..d62f682
--- /dev/null
+++ b/girepository/cmph/chd_structs.h
@@ -0,0 +1,21 @@
+#ifndef __CMPH_CHD_STRUCTS_H__
+#define __CMPH_CHD_STRUCTS_H__
+
+#include "chd_structs_ph.h"
+#include "chd_ph.h"
+#include "compressed_rank.h"
+
+struct __chd_data_t
+{
+	cmph_uint32 packed_cr_size;
+	cmph_uint8 * packed_cr; // packed compressed rank structure to control the number of zeros in a bit vector
+	
+	cmph_uint32 packed_chd_phf_size;
+	cmph_uint8 * packed_chd_phf;
+};
+
+struct __chd_config_data_t
+{	
+	cmph_config_t *chd_ph;     // chd_ph algorithm must be used here
+};
+#endif
diff --git a/girepository/cmph/chd_structs_ph.h b/girepository/cmph/chd_structs_ph.h
new file mode 100644
index 0000000..d869218
--- /dev/null
+++ b/girepository/cmph/chd_structs_ph.h
@@ -0,0 +1,29 @@
+#ifndef __CMPH_CHD_PH_STRUCTS_H__
+#define __CMPH_CHD_PH_STRUCTS_H__
+
+#include "hash_state.h"
+#include "compressed_seq.h"
+
+struct __chd_ph_data_t
+{
+	compressed_seq_t * cs;	// compressed displacement values
+	cmph_uint32 nbuckets;	// number of buckets
+	cmph_uint32 n;		// number of bins
+	hash_state_t *hl;	// linear hash function
+};
+
+struct __chd_ph_config_data_t
+{
+	CMPH_HASH hashfunc;	// linear hash function to be used
+	compressed_seq_t * cs;	// compressed displacement values
+	cmph_uint32 nbuckets;	// number of buckets
+	cmph_uint32 n;		// number of bins
+	hash_state_t *hl;	// linear hash function
+	
+	cmph_uint32 m;		// number of keys
+	cmph_uint8 use_h;	// flag to indicate the of use of a heuristic (use_h = 1)
+	cmph_uint32 keys_per_bin;//maximum number of keys per bin 
+	cmph_uint32 keys_per_bucket; // average number of keys per bucket
+	cmph_uint8 *occup_table;     // table that indicates occupied positions	
+};
+#endif
diff --git a/girepository/cmph/chm.c b/girepository/cmph/chm.c
new file mode 100644
index 0000000..e03cca8
--- /dev/null
+++ b/girepository/cmph/chm.c
@@ -0,0 +1,381 @@
+#include "graph.h"
+#include "chm.h"
+#include "cmph_structs.h"
+#include "chm_structs.h"
+#include "hash.h"
+#include "bitbool.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+
+//#define DEBUG
+#include "debug.h"
+
+static int chm_gen_edges(cmph_config_t *mph);
+static void chm_traverse(chm_config_data_t *chm, cmph_uint8 *visited, cmph_uint32 v);
+
+chm_config_data_t *chm_config_new()
+{
+	chm_config_data_t *chm = NULL;
+	chm = (chm_config_data_t *)malloc(sizeof(chm_config_data_t));
+	assert(chm);
+	memset(chm, 0, sizeof(chm_config_data_t));
+	chm->hashfuncs[0] = CMPH_HASH_JENKINS;
+	chm->hashfuncs[1] = CMPH_HASH_JENKINS;
+	chm->g = NULL;
+	chm->graph = NULL;
+	chm->hashes = NULL;
+	return chm;
+}
+void chm_config_destroy(cmph_config_t *mph)
+{
+	chm_config_data_t *data = (chm_config_data_t *)mph->data;
+	DEBUGP("Destroying algorithm dependent data\n");
+	free(data);
+}
+
+void chm_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs)
+{
+	chm_config_data_t *chm = (chm_config_data_t *)mph->data;
+	CMPH_HASH *hashptr = hashfuncs;
+	cmph_uint32 i = 0;
+	while(*hashptr != CMPH_HASH_COUNT)
+	{
+		if (i >= 2) break; //chm only uses two hash functions
+		chm->hashfuncs[i] = *hashptr;	
+		++i, ++hashptr;
+	}
+}
+
+cmph_t *chm_new(cmph_config_t *mph, double c)
+{
+	cmph_t *mphf = NULL;
+	chm_data_t *chmf = NULL;
+
+	cmph_uint32 i;
+	cmph_uint32 iterations = 20;
+	cmph_uint8 *visited = NULL;
+	chm_config_data_t *chm = (chm_config_data_t *)mph->data;
+	chm->m = mph->key_source->nkeys;
+	if (c == 0) c = 2.09;
+	chm->n = (cmph_uint32)ceil(c * mph->key_source->nkeys);	
+	DEBUGP("m (edges): %u n (vertices): %u c: %f\n", chm->m, chm->n, c);
+	chm->graph = graph_new(chm->n, chm->m);
+	DEBUGP("Created graph\n");
+
+	chm->hashes = (hash_state_t **)malloc(sizeof(hash_state_t *)*3);
+	for(i = 0; i < 3; ++i) chm->hashes[i] = NULL;
+	//Mapping step
+	if (mph->verbosity)
+	{
+		fprintf(stderr, "Entering mapping step for mph creation of %u keys with graph sized %u\n", chm->m, chm->n);
+	}
+	while(1)
+	{
+		int ok;
+		chm->hashes[0] = hash_state_new(chm->hashfuncs[0], chm->n);
+		chm->hashes[1] = hash_state_new(chm->hashfuncs[1], chm->n);
+		ok = chm_gen_edges(mph);
+		if (!ok)
+		{
+			--iterations;
+			hash_state_destroy(chm->hashes[0]);
+			chm->hashes[0] = NULL;
+			hash_state_destroy(chm->hashes[1]);
+			chm->hashes[1] = NULL;
+			DEBUGP("%u iterations remaining\n", iterations);
+			if (mph->verbosity)
+			{
+				fprintf(stderr, "Acyclic graph creation failure - %u iterations remaining\n", iterations);
+			}
+			if (iterations == 0) break;
+		} 
+		else break;	
+	}
+	if (iterations == 0)
+	{
+		graph_destroy(chm->graph);	
+		return NULL;
+	}
+
+	//Assignment step
+	if (mph->verbosity)
+	{
+		fprintf(stderr, "Starting assignment step\n");
+	}
+	DEBUGP("Assignment step\n");
+ 	visited = (cmph_uint8 *)malloc((size_t)(chm->n/8 + 1));
+	memset(visited, 0, (size_t)(chm->n/8 + 1));
+	free(chm->g);
+	chm->g = (cmph_uint32 *)malloc(chm->n * sizeof(cmph_uint32));
+	assert(chm->g);
+	for (i = 0; i < chm->n; ++i)
+	{
+	        if (!GETBIT(visited,i))
+		{
+			chm->g[i] = 0;
+			chm_traverse(chm, visited, i);
+		}
+	}
+	graph_destroy(chm->graph);	
+	free(visited);
+	chm->graph = NULL;
+
+	mphf = (cmph_t *)malloc(sizeof(cmph_t));
+	mphf->algo = mph->algo;
+	chmf = (chm_data_t *)malloc(sizeof(chm_data_t));
+	chmf->g = chm->g;
+	chm->g = NULL; //transfer memory ownership
+	chmf->hashes = chm->hashes;
+	chm->hashes = NULL; //transfer memory ownership
+	chmf->n = chm->n;
+	chmf->m = chm->m;
+	mphf->data = chmf;
+	mphf->size = chm->m;
+	DEBUGP("Successfully generated minimal perfect hash\n");
+	if (mph->verbosity)
+	{
+		fprintf(stderr, "Successfully generated minimal perfect hash function\n");
+	}
+	return mphf;
+}
+
+static void chm_traverse(chm_config_data_t *chm, cmph_uint8 *visited, cmph_uint32 v)
+{
+
+	graph_iterator_t it = graph_neighbors_it(chm->graph, v);
+	cmph_uint32 neighbor = 0;
+	SETBIT(visited,v);
+	
+	DEBUGP("Visiting vertex %u\n", v);
+	while((neighbor = graph_next_neighbor(chm->graph, &it)) != GRAPH_NO_NEIGHBOR)
+	{
+		DEBUGP("Visiting neighbor %u\n", neighbor);
+		if(GETBIT(visited,neighbor)) continue;
+		DEBUGP("Visiting neighbor %u\n", neighbor);
+		DEBUGP("Visiting edge %u->%u with id %u\n", v, neighbor, graph_edge_id(chm->graph, v, neighbor));
+		chm->g[neighbor] = graph_edge_id(chm->graph, v, neighbor) - chm->g[v];
+		DEBUGP("g is %u (%u - %u mod %u)\n", chm->g[neighbor], graph_edge_id(chm->graph, v, neighbor), chm->g[v], chm->m);
+		chm_traverse(chm, visited, neighbor);
+	}
+}
+		
+static int chm_gen_edges(cmph_config_t *mph)
+{
+	cmph_uint32 e;
+	chm_config_data_t *chm = (chm_config_data_t *)mph->data;
+	int cycles = 0;
+
+	DEBUGP("Generating edges for %u vertices with hash functions %s and %s\n", chm->n, cmph_hash_names[chm->hashfuncs[0]], cmph_hash_names[chm->hashfuncs[1]]);
+	graph_clear_edges(chm->graph);	
+	mph->key_source->rewind(mph->key_source->data);
+	for (e = 0; e < mph->key_source->nkeys; ++e)
+	{
+		cmph_uint32 h1, h2;
+		cmph_uint32 keylen;
+		char *key;
+		mph->key_source->read(mph->key_source->data, &key, &keylen);
+		h1 = hash(chm->hashes[0], key, keylen) % chm->n;
+		h2 = hash(chm->hashes[1], key, keylen) % chm->n;
+		if (h1 == h2) if (++h2 >= chm->n) h2 = 0;
+		if (h1 == h2) 
+		{
+			if (mph->verbosity) fprintf(stderr, "Self loop for key %u\n", e);
+			mph->key_source->dispose(mph->key_source->data, key, keylen);
+			return 0;
+		}
+		DEBUGP("Adding edge: %u -> %u for key %s\n", h1, h2, key);
+		mph->key_source->dispose(mph->key_source->data, key, keylen);
+		graph_add_edge(chm->graph, h1, h2);
+	}
+	cycles = graph_is_cyclic(chm->graph);
+	if (mph->verbosity && cycles) fprintf(stderr, "Cyclic graph generated\n");
+	DEBUGP("Looking for cycles: %u\n", cycles);
+
+	return ! cycles;
+}
+
+int chm_dump(cmph_t *mphf, FILE *fd)
+{
+	char *buf = NULL;
+	cmph_uint32 buflen;
+	cmph_uint32 two = 2; //number of hash functions
+	chm_data_t *data = (chm_data_t *)mphf->data;
+	register size_t nbytes;
+	
+	__cmph_dump(mphf, fd);
+
+	nbytes = fwrite(&two, sizeof(cmph_uint32), (size_t)1, fd);
+	hash_state_dump(data->hashes[0], &buf, &buflen);
+	DEBUGP("Dumping hash state with %u bytes to disk\n", buflen);
+	nbytes = fwrite(&buflen, sizeof(cmph_uint32), (size_t)1, fd);
+	nbytes = fwrite(buf, (size_t)buflen, (size_t)1, fd);
+	free(buf);
+
+	hash_state_dump(data->hashes[1], &buf, &buflen);
+	DEBUGP("Dumping hash state with %u bytes to disk\n", buflen);
+	nbytes = fwrite(&buflen, sizeof(cmph_uint32), (size_t)1, fd);
+	nbytes = fwrite(buf, (size_t)buflen, (size_t)1, fd);
+	free(buf);
+
+	nbytes = fwrite(&(data->n), sizeof(cmph_uint32), (size_t)1, fd);
+	nbytes = fwrite(&(data->m), sizeof(cmph_uint32), (size_t)1, fd);
+	
+	nbytes = fwrite(data->g, sizeof(cmph_uint32)*data->n, (size_t)1, fd);
+/*	#ifdef DEBUG
+	fprintf(stderr, "G: ");
+	for (i = 0; i < data->n; ++i) fprintf(stderr, "%u ", data->g[i]);
+	fprintf(stderr, "\n");
+	#endif*/
+	return 1;
+}
+
+void chm_load(FILE *f, cmph_t *mphf)
+{
+	cmph_uint32 nhashes;
+	char *buf = NULL;
+	cmph_uint32 buflen;
+	cmph_uint32 i;
+	chm_data_t *chm = (chm_data_t *)malloc(sizeof(chm_data_t));
+	register size_t nbytes;
+	DEBUGP("Loading chm mphf\n");
+	mphf->data = chm;
+	nbytes = fread(&nhashes, sizeof(cmph_uint32), (size_t)1, f);
+	chm->hashes = (hash_state_t **)malloc(sizeof(hash_state_t *)*(nhashes + 1));
+	chm->hashes[nhashes] = NULL;
+	DEBUGP("Reading %u hashes\n", nhashes);
+	for (i = 0; i < nhashes; ++i)
+	{
+		hash_state_t *state = NULL;
+		nbytes = fread(&buflen, sizeof(cmph_uint32), (size_t)1, f);
+		DEBUGP("Hash state has %u bytes\n", buflen);
+		buf = (char *)malloc((size_t)buflen);
+		nbytes = fread(buf, (size_t)buflen, (size_t)1, f);
+		state = hash_state_load(buf, buflen);
+		chm->hashes[i] = state;
+		free(buf);
+	}
+
+	DEBUGP("Reading m and n\n");
+	nbytes = fread(&(chm->n), sizeof(cmph_uint32), (size_t)1, f);	
+	nbytes = fread(&(chm->m), sizeof(cmph_uint32), (size_t)1, f);	
+
+	chm->g = (cmph_uint32 *)malloc(sizeof(cmph_uint32)*chm->n);
+	nbytes = fread(chm->g, chm->n*sizeof(cmph_uint32), (size_t)1, f);
+	#ifdef DEBUG
+	fprintf(stderr, "G: ");
+	for (i = 0; i < chm->n; ++i) fprintf(stderr, "%u ", chm->g[i]);
+	fprintf(stderr, "\n");
+	#endif
+	return;
+}
+		
+
+cmph_uint32 chm_search(cmph_t *mphf, const char *key, cmph_uint32 keylen)
+{
+	chm_data_t *chm = mphf->data;
+	cmph_uint32 h1 = hash(chm->hashes[0], key, keylen) % chm->n;
+	cmph_uint32 h2 = hash(chm->hashes[1], key, keylen) % chm->n;
+	DEBUGP("key: %s h1: %u h2: %u\n", key, h1, h2);
+	if (h1 == h2 && ++h2 >= chm->n) h2 = 0;
+	DEBUGP("key: %s g[h1]: %u g[h2]: %u edges: %u\n", key, chm->g[h1], chm->g[h2], chm->m);
+	return (chm->g[h1] + chm->g[h2]) % chm->m;
+}
+void chm_destroy(cmph_t *mphf)
+{
+	chm_data_t *data = (chm_data_t *)mphf->data;
+	free(data->g);	
+	hash_state_destroy(data->hashes[0]);
+	hash_state_destroy(data->hashes[1]);
+	free(data->hashes);
+	free(data);
+	free(mphf);
+}
+
+/** \fn void chm_pack(cmph_t *mphf, void *packed_mphf);
+ *  \brief Support the ability to pack a perfect hash function into a preallocated contiguous memory space pointed by packed_mphf.
+ *  \param mphf pointer to the resulting mphf
+ *  \param packed_mphf pointer to the contiguous memory area used to store the resulting mphf. The size of packed_mphf must be at least cmph_packed_size() 
+ */
+void chm_pack(cmph_t *mphf, void *packed_mphf)
+{
+	chm_data_t *data = (chm_data_t *)mphf->data;
+	cmph_uint8 * ptr = packed_mphf;
+
+	// packing h1 type
+	CMPH_HASH h1_type = hash_get_type(data->hashes[0]);
+	*((cmph_uint32 *) ptr) = h1_type;
+	ptr += sizeof(cmph_uint32);
+
+	// packing h1
+	hash_state_pack(data->hashes[0], ptr);
+	ptr += hash_state_packed_size(h1_type);
+
+	// packing h2 type
+	CMPH_HASH h2_type = hash_get_type(data->hashes[1]);
+	*((cmph_uint32 *) ptr) = h2_type;
+	ptr += sizeof(cmph_uint32);
+
+	// packing h2
+	hash_state_pack(data->hashes[1], ptr);
+	ptr += hash_state_packed_size(h2_type);
+
+	// packing n
+	*((cmph_uint32 *) ptr) = data->n;
+	ptr += sizeof(data->n);
+
+	// packing m
+	*((cmph_uint32 *) ptr) = data->m;
+	ptr += sizeof(data->m);
+
+	// packing g
+	memcpy(ptr, data->g, sizeof(cmph_uint32)*data->n);	
+}
+
+/** \fn cmph_uint32 chm_packed_size(cmph_t *mphf);
+ *  \brief Return the amount of space needed to pack mphf.
+ *  \param mphf pointer to a mphf
+ *  \return the size of the packed function or zero for failures
+ */ 
+cmph_uint32 chm_packed_size(cmph_t *mphf)
+{
+	chm_data_t *data = (chm_data_t *)mphf->data;
+	CMPH_HASH h1_type = hash_get_type(data->hashes[0]); 
+	CMPH_HASH h2_type = hash_get_type(data->hashes[1]); 
+
+	return (cmph_uint32)(sizeof(CMPH_ALGO) + hash_state_packed_size(h1_type) + hash_state_packed_size(h2_type) + 
+			4*sizeof(cmph_uint32) + sizeof(cmph_uint32)*data->n);
+}
+
+/** cmph_uint32 chm_search(void *packed_mphf, const char *key, cmph_uint32 keylen);
+ *  \brief Use the packed mphf to do a search. 
+ *  \param  packed_mphf pointer to the packed mphf
+ *  \param key key to be hashed
+ *  \param keylen key legth in bytes
+ *  \return The mphf value
+ */
+cmph_uint32 chm_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen)
+{
+	register cmph_uint8 *h1_ptr = packed_mphf;
+	register CMPH_HASH h1_type  = *((cmph_uint32 *)h1_ptr);
+	h1_ptr += 4;
+
+	register cmph_uint8 *h2_ptr = h1_ptr + hash_state_packed_size(h1_type);
+	register CMPH_HASH h2_type  = *((cmph_uint32 *)h2_ptr);
+	h2_ptr += 4;
+	
+	register cmph_uint32 *g_ptr = (cmph_uint32 *)(h2_ptr + hash_state_packed_size(h2_type));
+	
+	register cmph_uint32 n = *g_ptr++;  
+	register cmph_uint32 m = *g_ptr++;  
+	
+	register cmph_uint32 h1 = hash_packed(h1_ptr, h1_type, key, keylen) % n; 
+	register cmph_uint32 h2 = hash_packed(h2_ptr, h2_type, key, keylen) % n; 
+	DEBUGP("key: %s h1: %u h2: %u\n", key, h1, h2);
+	if (h1 == h2 && ++h2 >= n) h2 = 0;
+	DEBUGP("key: %s g[h1]: %u g[h2]: %u edges: %u\n", key, g_ptr[h1], g_ptr[h2], m);
+	return (g_ptr[h1] + g_ptr[h2]) % m;	
+}
diff --git a/girepository/cmph/chm.h b/girepository/cmph/chm.h
new file mode 100644
index 0000000..341be29
--- /dev/null
+++ b/girepository/cmph/chm.h
@@ -0,0 +1,42 @@
+#ifndef __CMPH_CHM_H__
+#define __CMPH_CHM_H__
+
+#include "cmph.h"
+
+typedef struct __chm_data_t chm_data_t;
+typedef struct __chm_config_data_t chm_config_data_t;
+
+chm_config_data_t *chm_config_new();
+void chm_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs);
+void chm_config_destroy(cmph_config_t *mph);
+cmph_t *chm_new(cmph_config_t *mph, double c);
+
+void chm_load(FILE *f, cmph_t *mphf);
+int chm_dump(cmph_t *mphf, FILE *f);
+void chm_destroy(cmph_t *mphf);
+cmph_uint32 chm_search(cmph_t *mphf, const char *key, cmph_uint32 keylen);
+
+/** \fn void chm_pack(cmph_t *mphf, void *packed_mphf);
+ *  \brief Support the ability to pack a perfect hash function into a preallocated contiguous memory space pointed by packed_mphf.
+ *  \param mphf pointer to the resulting mphf
+ *  \param packed_mphf pointer to the contiguous memory area used to store the resulting mphf. The size of packed_mphf must be at least cmph_packed_size() 
+ */
+void chm_pack(cmph_t *mphf, void *packed_mphf);
+
+/** \fn cmph_uint32 chm_packed_size(cmph_t *mphf);
+ *  \brief Return the amount of space needed to pack mphf.
+ *  \param mphf pointer to a mphf
+ *  \return the size of the packed function or zero for failures
+ */ 
+cmph_uint32 chm_packed_size(cmph_t *mphf);
+
+/** cmph_uint32 chm_search(void *packed_mphf, const char *key, cmph_uint32 keylen);
+ *  \brief Use the packed mphf to do a search. 
+ *  \param  packed_mphf pointer to the packed mphf
+ *  \param key key to be hashed
+ *  \param keylen key legth in bytes
+ *  \return The mphf value
+ */
+cmph_uint32 chm_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen);
+
+#endif
diff --git a/girepository/cmph/chm_structs.h b/girepository/cmph/chm_structs.h
new file mode 100644
index 0000000..fcad1bc
--- /dev/null
+++ b/girepository/cmph/chm_structs.h
@@ -0,0 +1,24 @@
+#ifndef __CMPH_CHM_STRUCTS_H__
+#define __CMPH_CHM_STRUCTS_H__
+
+#include "hash_state.h"
+
+struct __chm_data_t
+{
+	cmph_uint32 m; //edges (words) count
+	cmph_uint32 n; //vertex count
+	cmph_uint32 *g;
+	hash_state_t **hashes;
+};
+
+struct __chm_config_data_t
+{
+	CMPH_HASH hashfuncs[2];
+	cmph_uint32 m; //edges (words) count
+	cmph_uint32 n; //vertex count
+	graph_t *graph;
+	cmph_uint32 *g;
+	hash_state_t **hashes;
+};
+
+#endif
diff --git a/girepository/cmph/cmph.c b/girepository/cmph/cmph.c
new file mode 100644
index 0000000..cba735f
--- /dev/null
+++ b/girepository/cmph/cmph.c
@@ -0,0 +1,845 @@
+#include "cmph.h"
+#include "cmph_structs.h"
+#include "chm.h"
+#include "bmz.h" 
+#include "bmz8.h" 
+#include "brz.h" 
+#include "fch.h" 
+#include "bdz.h"
+#include "bdz_ph.h"
+#include "chd_ph.h"
+#include "chd.h"
+
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+//#define DEBUG
+#include "debug.h"
+
+const char *cmph_names[] = {"bmz", "bmz8", "chm", "brz", "fch", "bdz", "bdz_ph", "chd_ph", "chd", NULL };
+
+typedef struct 
+{
+	void *vector;
+	cmph_uint32 position; // access position when data is a vector	
+} cmph_vector_t;
+
+
+
+/** 
+ * Support a vector of struct as the source of keys.
+ *
+ * E.g. The keys could be the fieldB's in a vector of struct rec where 
+ * struct rec is defined as:
+ * struct rec {
+ *    fieldA;
+ *    fieldB;
+ *    fieldC;
+ * }
+ */
+typedef struct 
+{
+	void *vector;					/* Pointer to the vector of struct */
+	cmph_uint32 position; 			/* current position */
+	cmph_uint32 struct_size;       	/* The size of the struct */
+	cmph_uint32 key_offset;        	/* The byte offset of the key in the struct */
+	cmph_uint32 key_len;          	/* The length of the key */
+} cmph_struct_vector_t;
+
+
+static cmph_io_adapter_t *cmph_io_vector_new(void * vector, cmph_uint32 nkeys);
+static void cmph_io_vector_destroy(cmph_io_adapter_t * key_source);
+
+static cmph_io_adapter_t *cmph_io_struct_vector_new(void * vector, cmph_uint32 struct_size, cmph_uint32 key_offset, cmph_uint32 key_len, cmph_uint32 nkeys);
+static void cmph_io_struct_vector_destroy(cmph_io_adapter_t * key_source);
+
+static int key_nlfile_read(void *data, char **key, cmph_uint32 *keylen)
+{
+	FILE *fd = (FILE *)data;
+	*key = NULL;
+	*keylen = 0;
+	while(1)
+	{
+		char buf[BUFSIZ];
+		char *c = fgets(buf, BUFSIZ, fd); 
+		if (c == NULL) return -1;
+		if (feof(fd)) return -1;
+		*key = (char *)realloc(*key, *keylen + strlen(buf) + 1);
+		memcpy(*key + *keylen, buf, strlen(buf));
+		*keylen += (cmph_uint32)strlen(buf);
+		if (buf[strlen(buf) - 1] != '\n') continue;
+		break;
+	}
+	if ((*keylen) && (*key)[*keylen - 1] == '\n')
+	{
+		(*key)[(*keylen) - 1] = 0;
+		--(*keylen);
+	}
+	return (int)(*keylen);
+}
+
+static int key_byte_vector_read(void *data, char **key, cmph_uint32 *keylen)
+{
+	cmph_vector_t *cmph_vector = (cmph_vector_t *)data;
+	cmph_uint8 **keys_vd = (cmph_uint8 **)cmph_vector->vector;
+	size_t size;
+	memcpy(keylen, keys_vd[cmph_vector->position], sizeof(*keylen));
+	size = *keylen;
+	*key = (char *)malloc(size);
+	memcpy(*key, keys_vd[cmph_vector->position] + sizeof(*keylen), size);
+	cmph_vector->position = cmph_vector->position + 1;
+	return (int)(*keylen);
+
+}
+
+static int key_struct_vector_read(void *data, char **key, cmph_uint32 *keylen)
+{
+    cmph_struct_vector_t *cmph_struct_vector = (cmph_struct_vector_t *)data;
+    char *keys_vd = (char *)cmph_struct_vector->vector;
+    size_t size;
+    *keylen = cmph_struct_vector->key_len;
+    size = *keylen;
+    *key = (char *)malloc(size);
+    memcpy(*key, (keys_vd + (cmph_struct_vector->position * cmph_struct_vector->struct_size) + cmph_struct_vector->key_offset), size);
+    cmph_struct_vector->position = cmph_struct_vector->position + 1;
+    return (int)(*keylen);
+}
+
+static int key_vector_read(void *data, char **key, cmph_uint32 *keylen)
+{
+        cmph_vector_t *cmph_vector = (cmph_vector_t *)data;
+        char **keys_vd = (char **)cmph_vector->vector;
+	size_t size;
+        *keylen = (cmph_uint32)strlen(keys_vd[cmph_vector->position]);
+	size = *keylen;
+        *key = (char *)malloc(size + 1);
+        strcpy(*key, keys_vd[cmph_vector->position]);
+        cmph_vector->position = cmph_vector->position + 1;
+	return (int)(*keylen);
+
+}
+
+
+static void key_nlfile_dispose(void *data, char *key, cmph_uint32 keylen)
+{
+	free(key);
+}
+
+static void key_vector_dispose(void *data, char *key, cmph_uint32 keylen)
+{
+	free(key);
+}
+
+static void key_nlfile_rewind(void *data)
+{
+	FILE *fd = (FILE *)data;
+	rewind(fd);
+}
+
+static void key_struct_vector_rewind(void *data)
+{
+	cmph_struct_vector_t *cmph_struct_vector = (cmph_struct_vector_t *)data;
+	cmph_struct_vector->position = 0;
+}
+
+static void key_vector_rewind(void *data)
+{
+	cmph_vector_t *cmph_vector = (cmph_vector_t *)data;
+	cmph_vector->position = 0;
+}
+
+static cmph_uint32 count_nlfile_keys(FILE *fd)
+{
+	cmph_uint32 count = 0;
+	register char * ptr;
+	rewind(fd);
+	while(1)
+	{
+		char buf[BUFSIZ];
+		ptr = fgets(buf, BUFSIZ, fd); 
+		if (feof(fd)) break;
+		if (buf[strlen(buf) - 1] != '\n') continue;
+		++count;
+	}
+	rewind(fd);
+	return count;
+}
+
+cmph_io_adapter_t *cmph_io_nlfile_adapter(FILE * keys_fd)
+{
+  cmph_io_adapter_t * key_source = (cmph_io_adapter_t *)malloc(sizeof(cmph_io_adapter_t));
+  assert(key_source);
+  key_source->data = (void *)keys_fd;
+  key_source->nkeys = count_nlfile_keys(keys_fd);
+  key_source->read = key_nlfile_read;
+  key_source->dispose = key_nlfile_dispose;
+  key_source->rewind = key_nlfile_rewind;
+  return key_source;
+}
+
+void cmph_io_nlfile_adapter_destroy(cmph_io_adapter_t * key_source)
+{
+	free(key_source);
+}
+
+cmph_io_adapter_t *cmph_io_nlnkfile_adapter(FILE * keys_fd, cmph_uint32 nkeys)
+{
+  cmph_io_adapter_t * key_source = (cmph_io_adapter_t *)malloc(sizeof(cmph_io_adapter_t));
+  assert(key_source);
+  key_source->data = (void *)keys_fd;
+  key_source->nkeys = nkeys;
+  key_source->read = key_nlfile_read;
+  key_source->dispose = key_nlfile_dispose;
+  key_source->rewind = key_nlfile_rewind;
+  return key_source;
+}
+
+void cmph_io_nlnkfile_adapter_destroy(cmph_io_adapter_t * key_source)
+{
+	free(key_source);
+}
+
+
+static cmph_io_adapter_t *cmph_io_struct_vector_new(void * vector, cmph_uint32 struct_size, cmph_uint32 key_offset, cmph_uint32 key_len, cmph_uint32 nkeys)
+{
+	cmph_io_adapter_t * key_source = (cmph_io_adapter_t *)malloc(sizeof(cmph_io_adapter_t));
+	cmph_struct_vector_t * cmph_struct_vector = (cmph_struct_vector_t *)malloc(sizeof(cmph_struct_vector_t));
+	assert(key_source);
+	assert(cmph_struct_vector);
+	cmph_struct_vector->vector = vector;
+	cmph_struct_vector->position = 0;
+	cmph_struct_vector->struct_size = struct_size;
+	cmph_struct_vector->key_offset = key_offset;
+	cmph_struct_vector->key_len = key_len;
+	key_source->data = (void *)cmph_struct_vector;
+	key_source->nkeys = nkeys;
+	return key_source;
+}
+
+static void cmph_io_struct_vector_destroy(cmph_io_adapter_t * key_source)
+{
+	cmph_struct_vector_t *cmph_struct_vector = (cmph_struct_vector_t *)key_source->data;
+	cmph_struct_vector->vector = NULL;
+	free(cmph_struct_vector);
+	free(key_source);
+}
+
+static cmph_io_adapter_t *cmph_io_vector_new(void * vector, cmph_uint32 nkeys)
+{
+	cmph_io_adapter_t * key_source = (cmph_io_adapter_t *)malloc(sizeof(cmph_io_adapter_t));
+	cmph_vector_t * cmph_vector = (cmph_vector_t *)malloc(sizeof(cmph_vector_t));
+	assert(key_source);
+	assert(cmph_vector);
+	cmph_vector->vector = vector;
+	cmph_vector->position = 0;
+	key_source->data = (void *)cmph_vector;
+	key_source->nkeys = nkeys;
+	return key_source;
+}
+
+static void cmph_io_vector_destroy(cmph_io_adapter_t * key_source)
+{
+	cmph_vector_t *cmph_vector = (cmph_vector_t *)key_source->data;
+	cmph_vector->vector = NULL;
+	free(cmph_vector);
+	free(key_source);
+}
+
+cmph_io_adapter_t *cmph_io_byte_vector_adapter(cmph_uint8 ** vector, cmph_uint32 nkeys)
+{
+	cmph_io_adapter_t * key_source = cmph_io_vector_new(vector, nkeys);
+	key_source->read = key_byte_vector_read;
+	key_source->dispose = key_vector_dispose;
+	key_source->rewind = key_vector_rewind;
+	return key_source;
+}
+void cmph_io_byte_vector_adapter_destroy(cmph_io_adapter_t * key_source)
+{
+	cmph_io_vector_destroy(key_source);
+}
+
+cmph_io_adapter_t *cmph_io_struct_vector_adapter(void * vector, cmph_uint32 struct_size, cmph_uint32 key_offset, cmph_uint32 key_len, cmph_uint32 nkeys)
+{
+	cmph_io_adapter_t * key_source = cmph_io_struct_vector_new(vector, struct_size, key_offset, key_len, nkeys);
+	key_source->read = key_struct_vector_read;
+	key_source->dispose = key_vector_dispose;
+	key_source->rewind = key_struct_vector_rewind;
+	return key_source;	
+}
+
+void cmph_io_struct_vector_adapter_destroy(cmph_io_adapter_t * key_source)
+{
+	cmph_io_struct_vector_destroy(key_source);	
+}
+
+cmph_io_adapter_t *cmph_io_vector_adapter(char ** vector, cmph_uint32 nkeys)
+{
+	cmph_io_adapter_t * key_source = cmph_io_vector_new(vector, nkeys);
+	key_source->read = key_vector_read;
+	key_source->dispose = key_vector_dispose;
+	key_source->rewind = key_vector_rewind;
+	return key_source;
+}
+
+void cmph_io_vector_adapter_destroy(cmph_io_adapter_t * key_source)
+{
+	cmph_io_vector_destroy(key_source);
+}
+
+cmph_config_t *cmph_config_new(cmph_io_adapter_t *key_source)
+{
+	cmph_config_t *mph = NULL;
+	mph = __config_new(key_source);
+	assert(mph);
+	mph->algo = CMPH_CHM; // default value
+	mph->data = chm_config_new();
+	return mph;
+}
+
+void cmph_config_set_algo(cmph_config_t *mph, CMPH_ALGO algo)
+{
+	if (algo != mph->algo)
+	{
+		switch (mph->algo)
+		{
+			case CMPH_CHM:
+				chm_config_destroy(mph);
+				break;
+			case CMPH_BMZ:
+				bmz_config_destroy(mph);
+				break;
+			case CMPH_BMZ8:
+				bmz8_config_destroy(mph);
+				break;
+			case CMPH_BRZ:
+				brz_config_destroy(mph);
+				break;
+			case CMPH_FCH:
+				fch_config_destroy(mph);
+				break;
+			case CMPH_BDZ:
+				bdz_config_destroy(mph);
+				break;
+			case CMPH_BDZ_PH:
+				bdz_ph_config_destroy(mph);
+				break;
+			case CMPH_CHD_PH:
+				chd_ph_config_destroy(mph);
+				break;
+			case CMPH_CHD:
+				chd_config_destroy(mph);
+				break;
+			default:
+				assert(0);
+		}
+		switch(algo)
+		{
+			case CMPH_CHM:
+				mph->data = chm_config_new();
+				break;
+			case CMPH_BMZ:
+				mph->data = bmz_config_new();
+				break;
+			case CMPH_BMZ8:
+				mph->data = bmz8_config_new();
+				break;
+			case CMPH_BRZ:
+				mph->data = brz_config_new();
+				break;
+			case CMPH_FCH:
+				mph->data = fch_config_new();
+				break;
+			case CMPH_BDZ:
+				mph->data = bdz_config_new();
+				break;
+			case CMPH_BDZ_PH:
+				mph->data = bdz_ph_config_new();
+				break;
+			case CMPH_CHD_PH:
+				mph->data = chd_ph_config_new();
+				break;
+			case CMPH_CHD:
+				mph->data = chd_config_new(mph);
+				break;
+			default:
+				assert(0);
+		}
+	}
+	mph->algo = algo;
+}
+
+void cmph_config_set_tmp_dir(cmph_config_t *mph, cmph_uint8 *tmp_dir)
+{
+	if (mph->algo == CMPH_BRZ) 
+	{
+		brz_config_set_tmp_dir(mph, tmp_dir);
+	}
+}
+
+
+void cmph_config_set_mphf_fd(cmph_config_t *mph, FILE *mphf_fd)
+{
+	if (mph->algo == CMPH_BRZ) 
+	{
+		brz_config_set_mphf_fd(mph, mphf_fd);
+	}
+}
+
+void cmph_config_set_b(cmph_config_t *mph, cmph_uint32 b)
+{
+	if (mph->algo == CMPH_BRZ) 
+	{
+		brz_config_set_b(mph, b);
+	}
+	else if (mph->algo == CMPH_BDZ) 
+	{
+		bdz_config_set_b(mph, b);
+	}
+	else if (mph->algo == CMPH_CHD_PH) 
+	{
+		chd_ph_config_set_b(mph, b);
+	}
+	else if (mph->algo == CMPH_CHD) 
+	{
+		chd_config_set_b(mph, b);
+	}
+}
+
+void cmph_config_set_keys_per_bin(cmph_config_t *mph, cmph_uint32 keys_per_bin)
+{
+	if (mph->algo == CMPH_CHD_PH) 
+	{
+		chd_ph_config_set_keys_per_bin(mph, keys_per_bin);
+	}
+	else if (mph->algo == CMPH_CHD) 
+	{
+		chd_config_set_keys_per_bin(mph, keys_per_bin);
+	}
+}
+
+void cmph_config_set_memory_availability(cmph_config_t *mph, cmph_uint32 memory_availability)
+{
+	if (mph->algo == CMPH_BRZ) 
+	{
+		brz_config_set_memory_availability(mph, memory_availability);
+	}
+}
+
+void cmph_config_destroy(cmph_config_t *mph)
+{
+	if(mph)
+	{
+		DEBUGP("Destroying mph with algo %s\n", cmph_names[mph->algo]);
+		switch (mph->algo)
+		{
+			case CMPH_CHM:
+				chm_config_destroy(mph);
+				break;
+			case CMPH_BMZ: /* included -- Fabiano */
+				bmz_config_destroy(mph);
+				break;
+			case CMPH_BMZ8: /* included -- Fabiano */
+				bmz8_config_destroy(mph);
+				break;
+			case CMPH_BRZ: /* included -- Fabiano */
+				brz_config_destroy(mph);
+				break;
+			case CMPH_FCH: /* included -- Fabiano */
+				fch_config_destroy(mph);
+				break;
+			case CMPH_BDZ: /* included -- Fabiano */
+				bdz_config_destroy(mph);
+				break;
+			case CMPH_BDZ_PH: /* included -- Fabiano */
+				bdz_ph_config_destroy(mph);
+				break;
+			case CMPH_CHD_PH: /* included -- Fabiano */
+				chd_ph_config_destroy(mph);
+				break;
+			case CMPH_CHD: /* included -- Fabiano */
+				chd_config_destroy(mph);
+				break;
+			default:
+				assert(0);
+		}
+		__config_destroy(mph);
+	}
+}
+
+void cmph_config_set_verbosity(cmph_config_t *mph, cmph_uint32 verbosity)
+{
+	mph->verbosity = verbosity;
+}
+
+void cmph_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs)
+{
+	switch (mph->algo)
+	{
+		case CMPH_CHM:
+			chm_config_set_hashfuncs(mph, hashfuncs);
+			break;
+		case CMPH_BMZ: /* included -- Fabiano */
+			bmz_config_set_hashfuncs(mph, hashfuncs);
+			break;
+		case CMPH_BMZ8: /* included -- Fabiano */
+			bmz8_config_set_hashfuncs(mph, hashfuncs);
+			break;
+		case CMPH_BRZ: /* included -- Fabiano */
+			brz_config_set_hashfuncs(mph, hashfuncs);
+			break;
+		case CMPH_FCH: /* included -- Fabiano */
+			fch_config_set_hashfuncs(mph, hashfuncs);
+			break;
+		case CMPH_BDZ: /* included -- Fabiano */
+			bdz_config_set_hashfuncs(mph, hashfuncs);
+			break;
+		case CMPH_BDZ_PH: /* included -- Fabiano */
+			bdz_ph_config_set_hashfuncs(mph, hashfuncs);
+			break;
+		case CMPH_CHD_PH: /* included -- Fabiano */
+			chd_ph_config_set_hashfuncs(mph, hashfuncs);
+			break;
+		case CMPH_CHD: /* included -- Fabiano */
+			chd_config_set_hashfuncs(mph, hashfuncs);
+			break;
+		default:
+			break;
+	}
+	return;
+}
+void cmph_config_set_graphsize(cmph_config_t *mph, double c)
+{
+	mph->c = c;
+	return;
+}
+
+cmph_t *cmph_new(cmph_config_t *mph)
+{
+	cmph_t *mphf = NULL;
+	double c = mph->c;
+
+	DEBUGP("Creating mph with algorithm %s\n", cmph_names[mph->algo]);
+	switch (mph->algo)	
+	{
+		case CMPH_CHM:
+			DEBUGP("Creating chm hash\n");
+			mphf = chm_new(mph, c);
+			break;
+		case CMPH_BMZ: /* included -- Fabiano */
+			DEBUGP("Creating bmz hash\n");
+			mphf = bmz_new(mph, c);
+			break;
+		case CMPH_BMZ8: /* included -- Fabiano */
+			DEBUGP("Creating bmz8 hash\n");
+			mphf = bmz8_new(mph, c);
+			break;
+		case CMPH_BRZ: /* included -- Fabiano */
+			DEBUGP("Creating brz hash\n");
+			if (c >= 2.0) brz_config_set_algo(mph, CMPH_FCH);
+			else brz_config_set_algo(mph, CMPH_BMZ8);
+			mphf = brz_new(mph, c);
+			break;
+		case CMPH_FCH: /* included -- Fabiano */
+			DEBUGP("Creating fch hash\n");
+			mphf = fch_new(mph, c);
+			break;
+		case CMPH_BDZ: /* included -- Fabiano */
+			DEBUGP("Creating bdz hash\n");
+			mphf = bdz_new(mph, c);
+			break;
+		case CMPH_BDZ_PH: /* included -- Fabiano */
+			DEBUGP("Creating bdz_ph hash\n");
+			mphf = bdz_ph_new(mph, c);
+			break;
+		case CMPH_CHD_PH: /* included -- Fabiano */
+			DEBUGP("Creating chd_ph hash\n");
+			mphf = chd_ph_new(mph, c);
+			break;
+		case CMPH_CHD: /* included -- Fabiano */
+			DEBUGP("Creating chd hash\n");
+			mphf = chd_new(mph, c);
+			break;
+		default:
+			assert(0);
+	}
+	return mphf;
+}
+
+int cmph_dump(cmph_t *mphf, FILE *f)
+{
+	switch (mphf->algo)
+	{
+		case CMPH_CHM:
+			return chm_dump(mphf, f);
+		case CMPH_BMZ: /* included -- Fabiano */
+			return bmz_dump(mphf, f);
+		case CMPH_BMZ8: /* included -- Fabiano */
+			return bmz8_dump(mphf, f);
+		case CMPH_BRZ: /* included -- Fabiano */
+			return brz_dump(mphf, f);
+		case CMPH_FCH: /* included -- Fabiano */
+			return fch_dump(mphf, f);
+		case CMPH_BDZ: /* included -- Fabiano */
+			return bdz_dump(mphf, f);
+		case CMPH_BDZ_PH: /* included -- Fabiano */
+			return bdz_ph_dump(mphf, f);
+		case CMPH_CHD_PH: /* included -- Fabiano */
+			return chd_ph_dump(mphf, f);
+		case CMPH_CHD: /* included -- Fabiano */
+			return chd_dump(mphf, f);
+		default:
+			assert(0);
+	}
+	assert(0);
+	return 0;
+}
+cmph_t *cmph_load(FILE *f)
+{
+	cmph_t *mphf = NULL;
+	DEBUGP("Loading mphf generic parts\n");
+	mphf =  __cmph_load(f);
+	if (mphf == NULL) return NULL;
+	DEBUGP("Loading mphf algorithm dependent parts\n");
+
+	switch (mphf->algo)
+	{
+		case CMPH_CHM:
+			chm_load(f, mphf);
+			break;
+		case CMPH_BMZ: /* included -- Fabiano */
+			DEBUGP("Loading bmz algorithm dependent parts\n");
+			bmz_load(f, mphf);
+			break;
+		case CMPH_BMZ8: /* included -- Fabiano */
+			DEBUGP("Loading bmz8 algorithm dependent parts\n");
+			bmz8_load(f, mphf);
+			break;
+		case CMPH_BRZ: /* included -- Fabiano */
+			DEBUGP("Loading brz algorithm dependent parts\n");
+			brz_load(f, mphf);
+			break;
+		case CMPH_FCH: /* included -- Fabiano */
+			DEBUGP("Loading fch algorithm dependent parts\n");
+			fch_load(f, mphf);
+			break;
+		case CMPH_BDZ: /* included -- Fabiano */
+			DEBUGP("Loading bdz algorithm dependent parts\n");
+			bdz_load(f, mphf);
+			break;
+		case CMPH_BDZ_PH: /* included -- Fabiano */
+			DEBUGP("Loading bdz_ph algorithm dependent parts\n");
+			bdz_ph_load(f, mphf);
+			break;
+		case CMPH_CHD_PH: /* included -- Fabiano */
+			DEBUGP("Loading chd_ph algorithm dependent parts\n");
+			chd_ph_load(f, mphf);
+			break;
+		case CMPH_CHD: /* included -- Fabiano */
+			DEBUGP("Loading chd algorithm dependent parts\n");
+			chd_load(f, mphf);
+			break;
+		default:
+			assert(0);
+	}
+	DEBUGP("Loaded mphf\n");
+	return mphf;
+}
+
+
+cmph_uint32 cmph_search(cmph_t *mphf, const char *key, cmph_uint32 keylen)
+{
+   	DEBUGP("mphf algorithm: %u \n", mphf->algo);
+	switch(mphf->algo)
+	{
+		case CMPH_CHM:
+			return chm_search(mphf, key, keylen);
+		case CMPH_BMZ: /* included -- Fabiano */
+		        DEBUGP("bmz algorithm search\n");		         
+		        return bmz_search(mphf, key, keylen);
+		case CMPH_BMZ8: /* included -- Fabiano */
+		        DEBUGP("bmz8 algorithm search\n");		         
+		        return bmz8_search(mphf, key, keylen);
+		case CMPH_BRZ: /* included -- Fabiano */
+		        DEBUGP("brz algorithm search\n");		         
+		        return brz_search(mphf, key, keylen);
+		case CMPH_FCH: /* included -- Fabiano */
+		        DEBUGP("fch algorithm search\n");		         
+		        return fch_search(mphf, key, keylen);
+		case CMPH_BDZ: /* included -- Fabiano */
+		        DEBUGP("bdz algorithm search\n");		         
+		        return bdz_search(mphf, key, keylen);
+		case CMPH_BDZ_PH: /* included -- Fabiano */
+		        DEBUGP("bdz_ph algorithm search\n");		         
+		        return bdz_ph_search(mphf, key, keylen);
+		case CMPH_CHD_PH: /* included -- Fabiano */
+		        DEBUGP("chd_ph algorithm search\n");		         
+		        return chd_ph_search(mphf, key, keylen);
+		case CMPH_CHD: /* included -- Fabiano */
+		        DEBUGP("chd algorithm search\n");		         
+		        return chd_search(mphf, key, keylen);
+		default:
+			assert(0);
+	}
+	assert(0);
+	return 0;
+}
+
+cmph_uint32 cmph_size(cmph_t *mphf)
+{
+	return mphf->size;
+}
+	
+void cmph_destroy(cmph_t *mphf)
+{
+	switch(mphf->algo)
+	{
+		case CMPH_CHM:
+			chm_destroy(mphf);
+			return;
+		case CMPH_BMZ: /* included -- Fabiano */
+			bmz_destroy(mphf);
+			return;
+		case CMPH_BMZ8: /* included -- Fabiano */
+			bmz8_destroy(mphf);
+			return;
+		case CMPH_BRZ: /* included -- Fabiano */
+			brz_destroy(mphf);
+			return;
+		case CMPH_FCH: /* included -- Fabiano */
+			fch_destroy(mphf);
+			return;
+		case CMPH_BDZ: /* included -- Fabiano */
+			bdz_destroy(mphf);
+			return;
+		case CMPH_BDZ_PH: /* included -- Fabiano */
+			bdz_ph_destroy(mphf);
+			return;
+		case CMPH_CHD_PH: /* included -- Fabiano */
+			chd_ph_destroy(mphf);
+			return;
+		case CMPH_CHD: /* included -- Fabiano */
+			chd_destroy(mphf);
+			return;
+		default: 
+			assert(0);
+	}
+	assert(0);
+	return;
+}
+
+
+/** \fn void cmph_pack(cmph_t *mphf, void *packed_mphf);
+ *  \brief Support the ability to pack a perfect hash function into a preallocated contiguous memory space pointed by packed_mphf.
+ *  \param mphf pointer to the resulting mphf
+ *  \param packed_mphf pointer to the contiguous memory area used to store the resulting mphf. The size of packed_mphf must be at least cmph_packed_size() 
+ */
+void cmph_pack(cmph_t *mphf, void *packed_mphf)
+{
+	// packing algorithm type to be used in cmph.c
+	cmph_uint32 * ptr = (cmph_uint32 *) packed_mphf; 
+	*ptr++ = mphf->algo;
+	DEBUGP("mphf->algo = %u\n", mphf->algo);
+	switch(mphf->algo)
+	{
+		case CMPH_CHM:
+			chm_pack(mphf, ptr);
+			break;
+		case CMPH_BMZ: /* included -- Fabiano */
+			bmz_pack(mphf, ptr);
+			break;
+		case CMPH_BMZ8: /* included -- Fabiano */
+			bmz8_pack(mphf, ptr);
+			break;
+		case CMPH_BRZ: /* included -- Fabiano */
+			brz_pack(mphf, ptr);
+			break;
+		case CMPH_FCH: /* included -- Fabiano */
+			fch_pack(mphf, ptr);
+			break;
+		case CMPH_BDZ: /* included -- Fabiano */
+			bdz_pack(mphf, ptr);
+			break;
+		case CMPH_BDZ_PH: /* included -- Fabiano */
+			bdz_ph_pack(mphf, ptr);
+			break;
+		case CMPH_CHD_PH: /* included -- Fabiano */
+			chd_ph_pack(mphf, ptr);
+			break;
+		case CMPH_CHD: /* included -- Fabiano */
+			chd_pack(mphf, ptr);
+			break;
+		default: 
+			assert(0);
+	}
+	return;
+}
+
+/** \fn cmph_uint32 cmph_packed_size(cmph_t *mphf);
+ *  \brief Return the amount of space needed to pack mphf.
+ *  \param mphf pointer to a mphf
+ *  \return the size of the packed function or zero for failures
+ */ 
+cmph_uint32 cmph_packed_size(cmph_t *mphf)
+{
+	switch(mphf->algo)
+	{
+		case CMPH_CHM:
+			return chm_packed_size(mphf);
+		case CMPH_BMZ: /* included -- Fabiano */
+			return bmz_packed_size(mphf);
+		case CMPH_BMZ8: /* included -- Fabiano */
+			return bmz8_packed_size(mphf);
+		case CMPH_BRZ: /* included -- Fabiano */
+			return brz_packed_size(mphf);
+		case CMPH_FCH: /* included -- Fabiano */
+			return fch_packed_size(mphf);
+		case CMPH_BDZ: /* included -- Fabiano */
+			return bdz_packed_size(mphf);
+		case CMPH_BDZ_PH: /* included -- Fabiano */
+			return bdz_ph_packed_size(mphf);
+		case CMPH_CHD_PH: /* included -- Fabiano */
+			return chd_ph_packed_size(mphf);
+		case CMPH_CHD: /* included -- Fabiano */
+			return chd_packed_size(mphf);
+		default: 
+			assert(0);
+	}
+	return 0; // FAILURE
+}
+
+/** cmph_uint32 cmph_search(void *packed_mphf, const char *key, cmph_uint32 keylen);
+ *  \brief Use the packed mphf to do a search. 
+ *  \param  packed_mphf pointer to the packed mphf
+ *  \param key key to be hashed
+ *  \param keylen key legth in bytes
+ *  \return The mphf value
+ */
+cmph_uint32 cmph_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen)
+{
+	cmph_uint32 *ptr = (cmph_uint32 *)packed_mphf;
+//	fprintf(stderr, "algo:%u\n", *ptr);
+	switch(*ptr)
+	{
+		case CMPH_CHM:
+			return chm_search_packed(++ptr, key, keylen);
+		case CMPH_BMZ: /* included -- Fabiano */
+			return bmz_search_packed(++ptr, key, keylen);
+		case CMPH_BMZ8: /* included -- Fabiano */
+			return bmz8_search_packed(++ptr, key, keylen);
+		case CMPH_BRZ: /* included -- Fabiano */
+			return brz_search_packed(++ptr, key, keylen);
+		case CMPH_FCH: /* included -- Fabiano */
+			return fch_search_packed(++ptr, key, keylen);
+		case CMPH_BDZ: /* included -- Fabiano */
+			return bdz_search_packed(++ptr, key, keylen);
+		case CMPH_BDZ_PH: /* included -- Fabiano */
+			return bdz_ph_search_packed(++ptr, key, keylen);
+		case CMPH_CHD_PH: /* included -- Fabiano */
+			return chd_ph_search_packed(++ptr, key, keylen);
+		case CMPH_CHD: /* included -- Fabiano */
+			return chd_search_packed(++ptr, key, keylen);
+		default: 
+			assert(0);
+	}
+	return 0; // FAILURE
+}
diff --git a/girepository/cmph/cmph.h b/girepository/cmph/cmph.h
new file mode 100644
index 0000000..1bc009e
--- /dev/null
+++ b/girepository/cmph/cmph.h
@@ -0,0 +1,112 @@
+#ifndef __CMPH_H__
+#define __CMPH_H__
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "cmph_types.h"
+
+typedef struct __config_t cmph_config_t;
+typedef struct __cmph_t cmph_t;
+
+typedef struct 
+{
+        void *data;
+        cmph_uint32 nkeys;
+        int (*read)(void *, char **, cmph_uint32 *);
+        void (*dispose)(void *, char *, cmph_uint32);
+        void (*rewind)(void *);
+} cmph_io_adapter_t;
+
+/** Adapter pattern API **/
+/* please call free() in the created adapters */
+cmph_io_adapter_t *cmph_io_nlfile_adapter(FILE * keys_fd);
+void cmph_io_nlfile_adapter_destroy(cmph_io_adapter_t * key_source);
+
+cmph_io_adapter_t *cmph_io_nlnkfile_adapter(FILE * keys_fd, cmph_uint32 nkeys);
+void cmph_io_nlnkfile_adapter_destroy(cmph_io_adapter_t * key_source);
+
+cmph_io_adapter_t *cmph_io_vector_adapter(char ** vector, cmph_uint32 nkeys);
+void cmph_io_vector_adapter_destroy(cmph_io_adapter_t * key_source);
+
+cmph_io_adapter_t *cmph_io_byte_vector_adapter(cmph_uint8 ** vector, cmph_uint32 nkeys);
+void cmph_io_byte_vector_adapter_destroy(cmph_io_adapter_t * key_source);
+
+cmph_io_adapter_t *cmph_io_struct_vector_adapter(void * vector, 
+                                                 cmph_uint32 struct_size, 
+                                                 cmph_uint32 key_offset, 
+                                                 cmph_uint32 key_len, 
+                                                 cmph_uint32 nkeys);
+
+void cmph_io_struct_vector_adapter_destroy(cmph_io_adapter_t * key_source);
+
+/** Hash configuration API **/
+cmph_config_t *cmph_config_new(cmph_io_adapter_t *key_source);
+void cmph_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs);
+void cmph_config_set_verbosity(cmph_config_t *mph, cmph_uint32 verbosity);
+void cmph_config_set_graphsize(cmph_config_t *mph, double c);
+void cmph_config_set_algo(cmph_config_t *mph, CMPH_ALGO algo);
+void cmph_config_set_tmp_dir(cmph_config_t *mph, cmph_uint8 *tmp_dir);
+void cmph_config_set_mphf_fd(cmph_config_t *mph, FILE *mphf_fd);
+void cmph_config_set_b(cmph_config_t *mph, cmph_uint32 b);
+void cmph_config_set_keys_per_bin(cmph_config_t *mph, cmph_uint32 keys_per_bin);
+void cmph_config_set_memory_availability(cmph_config_t *mph, cmph_uint32 memory_availability);
+void cmph_config_destroy(cmph_config_t *mph);
+
+/** Hash API **/
+cmph_t *cmph_new(cmph_config_t *mph);
+
+/** cmph_uint32 cmph_search(cmph_t *mphf, const char *key, cmph_uint32 keylen);
+ *  \brief Computes the mphf value. 
+ *  \param mphf pointer to the resulting function
+ *  \param key is the key to be hashed
+ *  \param keylen is the key legth in bytes
+ *  \return The mphf value
+ */
+cmph_uint32 cmph_search(cmph_t *mphf, const char *key, cmph_uint32 keylen);
+
+cmph_uint32 cmph_size(cmph_t *mphf);
+void cmph_destroy(cmph_t *mphf);
+
+/** Hash serialization/deserialization */
+int cmph_dump(cmph_t *mphf, FILE *f);
+cmph_t *cmph_load(FILE *f);
+
+/** \fn void cmph_pack(cmph_t *mphf, void *packed_mphf);
+ *  \brief Support the ability to pack a perfect hash function into a preallocated contiguous memory space pointed by packed_mphf.
+ *  \param mphf pointer to the resulting mphf
+ *  \param packed_mphf pointer to the contiguous memory area used to store the 
+ *  \param resulting mphf. The size of packed_mphf must be at least cmph_packed_size() 
+ */
+void cmph_pack(cmph_t *mphf, void *packed_mphf);
+
+/** \fn cmph_uint32 cmph_packed_size(cmph_t *mphf);
+ *  \brief Return the amount of space needed to pack mphf.
+ *  \param mphf pointer to a mphf
+ *  \return the size of the packed function or zero for failures
+ */
+cmph_uint32 cmph_packed_size(cmph_t *mphf);
+
+/** cmph_uint32 cmph_search(void *packed_mphf, const char *key, cmph_uint32 keylen);
+ *  \brief Use the packed mphf to do a search. 
+ *  \param  packed_mphf pointer to the packed mphf
+ *  \param key key to be hashed
+ *  \param keylen key legth in bytes
+ *  \return The mphf value
+ */
+cmph_uint32 cmph_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen);
+
+// TIMING functions. To use the macro CMPH_TIMING must be defined
+#include "cmph_time.h"
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/girepository/cmph/cmph_structs.c b/girepository/cmph/cmph_structs.c
new file mode 100644
index 0000000..b563424
--- /dev/null
+++ b/girepository/cmph/cmph_structs.c
@@ -0,0 +1,69 @@
+#include "cmph_structs.h"
+
+#include <string.h>
+
+//#define DEBUG
+#include "debug.h"
+
+cmph_config_t *__config_new(cmph_io_adapter_t *key_source)
+{
+	cmph_config_t *mph = (cmph_config_t *)malloc(sizeof(cmph_config_t));
+	memset(mph, 0, sizeof(cmph_config_t));
+	if (mph == NULL) return NULL;
+	mph->key_source = key_source;
+	mph->verbosity = 0;
+	mph->data = NULL;
+	mph->c = 0;
+	return mph;
+}
+
+void __config_destroy(cmph_config_t *mph)
+{
+	free(mph);
+}
+
+void __cmph_dump(cmph_t *mphf, FILE *fd)
+{
+	register size_t nbytes;
+	nbytes = fwrite(cmph_names[mphf->algo], (size_t)(strlen(cmph_names[mphf->algo]) + 1), (size_t)1, fd);
+	nbytes = fwrite(&(mphf->size), sizeof(mphf->size), (size_t)1, fd);
+}
+cmph_t *__cmph_load(FILE *f) 
+{
+	cmph_t *mphf = NULL;
+	cmph_uint32 i;
+	char algo_name[BUFSIZ];
+	char *ptr = algo_name;
+	CMPH_ALGO algo = CMPH_COUNT;
+	register size_t nbytes;
+	
+	DEBUGP("Loading mphf\n");
+	while(1)
+	{
+		size_t c = fread(ptr, (size_t)1, (size_t)1, f);
+		if (c != 1) return NULL;
+		if (*ptr == 0) break;
+		++ptr;
+	}
+	for(i = 0; i < CMPH_COUNT; ++i)
+	{
+		if (strcmp(algo_name, cmph_names[i]) == 0)
+		{
+			algo = i;
+		}
+	}
+	if (algo == CMPH_COUNT) 
+	{
+		DEBUGP("Algorithm %s not found\n", algo_name);
+		return NULL;
+	}
+	mphf = (cmph_t *)malloc(sizeof(cmph_t));
+	mphf->algo = algo;
+	nbytes = fread(&(mphf->size), sizeof(mphf->size), (size_t)1, f);
+	mphf->data = NULL;
+	DEBUGP("Algorithm is %s and mphf is sized %u\n", cmph_names[algo],  mphf->size);
+
+	return mphf;
+}
+
+
diff --git a/girepository/cmph/cmph_structs.h b/girepository/cmph/cmph_structs.h
new file mode 100644
index 0000000..88fafb6
--- /dev/null
+++ b/girepository/cmph/cmph_structs.h
@@ -0,0 +1,33 @@
+#ifndef __CMPH_STRUCTS_H__
+#define __CMPH_STRUCTS_H__
+
+#include "cmph.h"
+
+/** Hash generation algorithm data
+  */
+struct __config_t
+{
+        CMPH_ALGO algo;
+        cmph_io_adapter_t *key_source;
+        cmph_uint32 verbosity;
+        double c;
+        void *data; // algorithm dependent data
+};
+
+/** Hash querying algorithm data
+  */
+struct __cmph_t
+{
+        CMPH_ALGO algo;
+        cmph_uint32 size;
+        cmph_io_adapter_t *key_source;
+        void *data; // algorithm dependent data
+};
+
+cmph_config_t *__config_new(cmph_io_adapter_t *key_source);
+void __config_destroy(cmph_config_t*);
+void __cmph_dump(cmph_t *mphf, FILE *);
+cmph_t *__cmph_load(FILE *f);
+
+
+#endif
diff --git a/girepository/cmph/cmph_time.h b/girepository/cmph/cmph_time.h
new file mode 100644
index 0000000..d801809
--- /dev/null
+++ b/girepository/cmph/cmph_time.h
@@ -0,0 +1,62 @@
+#ifdef ELAPSED_TIME_IN_SECONDS
+#undef ELAPSED_TIME_IN_SECONDS
+#endif
+
+#ifdef ELAPSED_TIME_IN_uSECONDS
+#undef ELAPSED_TIME_IN_uSECONDS
+#endif
+
+#ifdef WIN32
+// include headers to use gettimeofday
+#else
+	#ifdef __GNUC__
+	#include <sys/time.h>
+	#include <sys/resource.h>
+	#endif
+#endif
+
+#ifdef __GNUC__
+	#ifndef __CMPH_TIME_H__
+		#define __CMPH_TIME_H__
+		static inline void elapsed_time_in_seconds(double * elapsed_time)
+		{
+			struct timeval e_time;
+			if (gettimeofday(&e_time, NULL) < 0) {
+				return;
+			}
+			*elapsed_time =  (double)e_time.tv_sec + ((double)e_time.tv_usec/1000000.0);
+		}
+		static inline void dummy_elapsed_time_in_seconds()
+		{
+		}
+		static inline void elapsed_time_in_useconds(cmph_uint64 * elapsed_time)
+		{
+			struct timeval e_time;
+			if (gettimeofday(&e_time, NULL) < 0) {
+				return;
+			}
+			*elapsed_time =  (cmph_uint64)(e_time.tv_sec*1000000 + e_time.tv_usec);
+		}
+		static inline void dummy_elapsed_time_in_useconds()
+		{
+		}	
+	#endif
+#endif
+
+#ifdef CMPH_TIMING
+	  #ifdef __GNUC__
+		  #define ELAPSED_TIME_IN_SECONDS elapsed_time_in_seconds
+		  #define ELAPSED_TIME_IN_uSECONDS elapsed_time_in_useconds
+	  #else
+		  #define ELAPSED_TIME_IN_SECONDS dummy_elapsed_time_in_seconds
+		  #define ELAPSED_TIME_IN_uSECONDS dummy_elapsed_time_in_useconds
+	  #endif
+#else
+	  #ifdef __GNUC__
+		  #define ELAPSED_TIME_IN_SECONDS
+		  #define ELAPSED_TIME_IN_uSECONDS
+	  #else
+		  #define ELAPSED_TIME_IN_SECONDS dummy_elapsed_time_in_seconds
+		  #define ELAPSED_TIME_IN_uSECONDS dummy_elapsed_time_in_useconds
+	  #endif
+#endif
diff --git a/girepository/cmph/cmph_types.h b/girepository/cmph/cmph_types.h
new file mode 100644
index 0000000..40f4332
--- /dev/null
+++ b/girepository/cmph/cmph_types.h
@@ -0,0 +1,42 @@
+#ifndef __CMPH_TYPES_H__
+#define __CMPH_TYPES_H__
+
+typedef char cmph_int8;
+typedef unsigned char cmph_uint8;
+
+typedef short cmph_int16;
+typedef unsigned short cmph_uint16;
+
+typedef int cmph_int32;
+typedef unsigned int cmph_uint32;
+
+#if defined(__ia64) || defined(__x86_64__)
+  /** \typedef long cmph_int64;
+   *  \brief 64-bit integer for a 64-bit achitecture.
+   */
+  typedef long cmph_int64;
+
+  /** \typedef unsigned long cmph_uint64;
+   *  \brief Unsigned 64-bit integer for a 64-bit achitecture.
+   */
+  typedef unsigned long cmph_uint64;
+#else
+  /** \typedef long long cmph_int64;
+   *  \brief 64-bit integer for a 32-bit achitecture.
+   */
+  typedef long long cmph_int64;
+
+  /** \typedef unsigned long long cmph_uint64;
+   *  \brief Unsigned 64-bit integer for a 32-bit achitecture.
+   */
+  typedef unsigned long long cmph_uint64;
+#endif
+
+typedef enum { CMPH_HASH_JENKINS, CMPH_HASH_COUNT } CMPH_HASH;
+extern const char *cmph_hash_names[];
+typedef enum { CMPH_BMZ, CMPH_BMZ8, CMPH_CHM, CMPH_BRZ, CMPH_FCH,
+               CMPH_BDZ, CMPH_BDZ_PH,
+               CMPH_CHD_PH, CMPH_CHD, CMPH_COUNT } CMPH_ALGO;
+extern const char *cmph_names[];
+
+#endif
diff --git a/girepository/cmph/compressed_rank.c b/girepository/cmph/compressed_rank.c
new file mode 100644
index 0000000..822b2e1
--- /dev/null
+++ b/girepository/cmph/compressed_rank.c
@@ -0,0 +1,321 @@
+#include<stdlib.h>
+#include<stdio.h>
+#include<limits.h>
+#include<string.h>
+#include"compressed_rank.h"
+#include"bitbool.h"
+// #define DEBUG
+#include"debug.h"
+static inline cmph_uint32 compressed_rank_i_log2(cmph_uint32 x)
+{
+	register cmph_uint32 res = 0;
+	
+	while(x > 1)
+	{
+		x >>= 1;
+		res++;
+	}
+	return res;
+};
+
+void compressed_rank_init(compressed_rank_t * cr)
+{
+	cr->max_val = 0;
+	cr->n = 0;
+	cr->rem_r = 0;
+	select_init(&cr->sel);
+	cr->vals_rems = 0;
+}
+
+void compressed_rank_destroy(compressed_rank_t * cr)
+{
+	free(cr->vals_rems);
+	cr->vals_rems = 0;
+	select_destroy(&cr->sel);
+}
+
+void compressed_rank_generate(compressed_rank_t * cr, cmph_uint32 * vals_table, cmph_uint32 n)
+{
+	register cmph_uint32 i,j;
+	register cmph_uint32 rems_mask;
+	register cmph_uint32 * select_vec = 0;
+	cr->n = n;
+	cr->max_val = vals_table[cr->n - 1];
+	cr->rem_r = compressed_rank_i_log2(cr->max_val/cr->n);
+	if(cr->rem_r == 0)
+	{
+		cr->rem_r = 1;
+	}
+	select_vec = (cmph_uint32 *) calloc(cr->max_val >> cr->rem_r, sizeof(cmph_uint32));
+	cr->vals_rems = (cmph_uint32 *) calloc(BITS_TABLE_SIZE(cr->n, cr->rem_r), sizeof(cmph_uint32));
+	rems_mask = (1U << cr->rem_r) - 1U;
+	
+	for(i = 0; i < cr->n; i++)
+	{
+		set_bits_value(cr->vals_rems, i, vals_table[i] & rems_mask, cr->rem_r, rems_mask);
+	}
+
+	for(i = 1, j = 0; i <= cr->max_val >> cr->rem_r; i++)
+	{
+		while(i > (vals_table[j] >> cr->rem_r))
+		{
+			j++;
+		}
+		select_vec[i - 1] = j;
+	};
+
+
+	// FABIANO: before it was (cr->total_length >> cr->rem_r) + 1. But I wiped out the + 1 because
+	// I changed the select structure to work up to m, instead of up to m - 1.
+	select_generate(&cr->sel, select_vec, cr->max_val >> cr->rem_r, cr->n);
+
+	free(select_vec);
+}
+
+cmph_uint32 compressed_rank_query(compressed_rank_t * cr, cmph_uint32 idx)
+{
+	register cmph_uint32 rems_mask;
+	register cmph_uint32 val_quot, val_rem;
+	register cmph_uint32 sel_res, rank;
+	
+	if(idx > cr->max_val)
+	{
+		return cr->n;
+	}
+	
+	val_quot = idx >> cr->rem_r; 	
+	rems_mask = (1U << cr->rem_r) - 1U; 
+	val_rem = idx & rems_mask; 
+	if(val_quot == 0)
+	{
+		rank = sel_res = 0;
+	}
+	else
+	{
+		sel_res = select_query(&cr->sel, val_quot - 1) + 1;
+		rank = sel_res - val_quot;
+	}
+	
+	do
+	{
+		if(GETBIT32(cr->sel.bits_vec, sel_res))
+		{
+			break;
+		}
+		if(get_bits_value(cr->vals_rems, rank, cr->rem_r, rems_mask) >= val_rem)
+		{
+			break;
+		}
+		sel_res++;
+		rank++;
+	} while(1);	
+	
+	return rank;
+}
+
+cmph_uint32 compressed_rank_get_space_usage(compressed_rank_t * cr)
+{
+	register cmph_uint32 space_usage = select_get_space_usage(&cr->sel);
+	space_usage += BITS_TABLE_SIZE(cr->n, cr->rem_r)*(cmph_uint32)sizeof(cmph_uint32)*8;
+	space_usage += 3*(cmph_uint32)sizeof(cmph_uint32)*8;
+	return space_usage;
+}
+
+void compressed_rank_dump(compressed_rank_t * cr, char **buf, cmph_uint32 *buflen)
+{
+	register cmph_uint32 sel_size = select_packed_size(&(cr->sel));
+	register cmph_uint32 vals_rems_size = BITS_TABLE_SIZE(cr->n, cr->rem_r) * (cmph_uint32)sizeof(cmph_uint32);
+	register cmph_uint32 pos = 0;
+	char * buf_sel = 0;
+	cmph_uint32 buflen_sel = 0;
+	
+	*buflen = 4*(cmph_uint32)sizeof(cmph_uint32) + sel_size +  vals_rems_size;
+	
+	DEBUGP("sel_size = %u\n", sel_size);
+	DEBUGP("vals_rems_size = %u\n", vals_rems_size);
+	
+	*buf = (char *)calloc(*buflen, sizeof(char));
+	
+	if (!*buf) 
+	{
+		*buflen = UINT_MAX;
+		return;
+	}
+	
+	// dumping max_val, n and rem_r
+	memcpy(*buf, &(cr->max_val), sizeof(cmph_uint32));
+	pos += (cmph_uint32)sizeof(cmph_uint32);
+	DEBUGP("max_val = %u\n", cr->max_val);
+
+	memcpy(*buf + pos, &(cr->n), sizeof(cmph_uint32));
+	pos += (cmph_uint32)sizeof(cmph_uint32);
+	DEBUGP("n = %u\n", cr->n);
+	
+	memcpy(*buf + pos, &(cr->rem_r), sizeof(cmph_uint32));
+	pos += (cmph_uint32)sizeof(cmph_uint32);
+	DEBUGP("rem_r = %u\n", cr->rem_r);
+
+	// dumping sel
+	select_dump(&cr->sel, &buf_sel, &buflen_sel);
+	memcpy(*buf + pos, &buflen_sel, sizeof(cmph_uint32));
+	pos += (cmph_uint32)sizeof(cmph_uint32);
+	DEBUGP("buflen_sel = %u\n", buflen_sel);
+
+	memcpy(*buf + pos, buf_sel, buflen_sel);
+	
+	#ifdef DEBUG	
+	cmph_uint32 i = 0; 
+	for(i = 0; i < buflen_sel; i++)
+	{
+	    DEBUGP("pos = %u  -- buf_sel[%u] = %u\n", pos, i, *(*buf + pos + i));
+	}
+	#endif
+	pos += buflen_sel;
+	
+	free(buf_sel);
+	
+	// dumping vals_rems
+	memcpy(*buf + pos, cr->vals_rems, vals_rems_size);
+	#ifdef DEBUG	
+	for(i = 0; i < vals_rems_size; i++)
+	{
+	    DEBUGP("pos = %u -- vals_rems_size = %u  -- vals_rems[%u] = %u\n", pos, vals_rems_size, i, *(*buf + pos + i));
+	}
+	#endif
+	pos += vals_rems_size;
+
+	DEBUGP("Dumped compressed rank structure with size %u bytes\n", *buflen);
+}
+
+void compressed_rank_load(compressed_rank_t * cr, const char *buf, cmph_uint32 buflen)
+{
+	register cmph_uint32 pos = 0;
+	cmph_uint32 buflen_sel = 0;
+	register cmph_uint32 vals_rems_size = 0;
+	
+	// loading max_val, n, and rem_r
+	memcpy(&(cr->max_val), buf, sizeof(cmph_uint32));
+	pos += (cmph_uint32)sizeof(cmph_uint32);
+	DEBUGP("max_val = %u\n", cr->max_val);
+
+	memcpy(&(cr->n), buf + pos, sizeof(cmph_uint32));
+	pos += (cmph_uint32)sizeof(cmph_uint32);
+	DEBUGP("n = %u\n", cr->n);
+
+	memcpy(&(cr->rem_r), buf + pos, sizeof(cmph_uint32));
+	pos += (cmph_uint32)sizeof(cmph_uint32);
+	DEBUGP("rem_r = %u\n", cr->rem_r);
+	
+	// loading sel
+	memcpy(&buflen_sel, buf + pos, sizeof(cmph_uint32));
+	pos += (cmph_uint32)sizeof(cmph_uint32);
+	DEBUGP("buflen_sel = %u\n", buflen_sel);
+
+	select_load(&cr->sel, buf + pos, buflen_sel);
+	#ifdef DEBUG	
+	cmph_uint32 i = 0;  
+	for(i = 0; i < buflen_sel; i++)
+	{
+	    DEBUGP("pos = %u  -- buf_sel[%u] = %u\n", pos, i, *(buf + pos + i));
+	}
+	#endif
+	pos += buflen_sel;
+	
+	// loading vals_rems
+	if(cr->vals_rems)
+	{
+		free(cr->vals_rems);
+	}
+	vals_rems_size = BITS_TABLE_SIZE(cr->n, cr->rem_r);
+	cr->vals_rems = (cmph_uint32 *) calloc(vals_rems_size, sizeof(cmph_uint32));
+	vals_rems_size *= 4;
+	memcpy(cr->vals_rems, buf + pos, vals_rems_size);
+	
+	#ifdef DEBUG	
+	for(i = 0; i < vals_rems_size; i++)
+	{
+	    DEBUGP("pos = %u -- vals_rems_size = %u  -- vals_rems[%u] = %u\n", pos, vals_rems_size, i, *(buf + pos + i));
+	}
+	#endif
+	pos += vals_rems_size;
+	
+	DEBUGP("Loaded compressed rank structure with size %u bytes\n", buflen);
+}
+
+
+
+void compressed_rank_pack(compressed_rank_t *cr, void *cr_packed)
+{
+	if (cr && cr_packed)
+	{
+		char *buf = NULL;
+		cmph_uint32 buflen = 0;
+		compressed_rank_dump(cr, &buf, &buflen);
+		memcpy(cr_packed, buf, buflen);
+		free(buf);
+	}
+}
+
+cmph_uint32 compressed_rank_packed_size(compressed_rank_t *cr)
+{
+	register cmph_uint32 sel_size = select_packed_size(&cr->sel);
+	register cmph_uint32 vals_rems_size = BITS_TABLE_SIZE(cr->n, cr->rem_r) * (cmph_uint32)sizeof(cmph_uint32);	
+	return 4 * (cmph_uint32)sizeof(cmph_uint32)  + sel_size +  vals_rems_size;
+}
+
+cmph_uint32 compressed_rank_query_packed(void * cr_packed, cmph_uint32 idx)
+{
+	// unpacking cr_packed
+	register cmph_uint32 *ptr = (cmph_uint32 *)cr_packed;
+	register cmph_uint32 max_val = *ptr++;
+	register cmph_uint32 n = *ptr++;
+	register cmph_uint32 rem_r = *ptr++;
+	register cmph_uint32 buflen_sel = *ptr++;
+	register cmph_uint32 * sel_packed = ptr;
+	
+	register cmph_uint32 * bits_vec = sel_packed + 2; // skipping n and m
+
+	register cmph_uint32 * vals_rems = (ptr += (buflen_sel >> 2)); 
+
+	// compressed sequence query computation
+	register cmph_uint32 rems_mask;
+	register cmph_uint32 val_quot, val_rem;
+	register cmph_uint32 sel_res, rank;
+	
+	if(idx > max_val)
+	{
+		return n;
+	}
+	
+	val_quot = idx >> rem_r; 	
+	rems_mask = (1U << rem_r) - 1U; 
+	val_rem = idx & rems_mask; 
+	if(val_quot == 0)
+	{
+		rank = sel_res = 0;
+	}
+	else
+	{
+		sel_res = select_query_packed(sel_packed, val_quot - 1) + 1;
+		rank = sel_res - val_quot;
+	}
+	
+	do
+	{
+		if(GETBIT32(bits_vec, sel_res))
+		{
+			break;
+		}
+		if(get_bits_value(vals_rems, rank, rem_r, rems_mask) >= val_rem)
+		{
+			break;
+		}
+		sel_res++;
+		rank++;
+	} while(1);	
+	
+	return rank;
+}
+
+
+
diff --git a/girepository/cmph/compressed_rank.h b/girepository/cmph/compressed_rank.h
new file mode 100644
index 0000000..bfe930d
--- /dev/null
+++ b/girepository/cmph/compressed_rank.h
@@ -0,0 +1,55 @@
+#ifndef __CMPH_COMPRESSED_RANK_H__
+#define __CMPH_COMPRESSED_RANK_H__
+
+#include "select.h"
+
+struct _compressed_rank_t
+{
+	cmph_uint32 max_val;
+	cmph_uint32 n; // number of values stored in vals_rems
+	// The length in bits of each value is decomposed into two compnents: the lg(n) MSBs are stored in rank_select data structure
+	// the remaining LSBs are stored in a table of n cells, each one of rem_r bits.
+	cmph_uint32 rem_r;
+	select_t sel;
+	cmph_uint32 * vals_rems;
+};
+
+typedef struct _compressed_rank_t compressed_rank_t;
+
+void compressed_rank_init(compressed_rank_t * cr);
+
+void compressed_rank_destroy(compressed_rank_t * cr);
+ 
+void compressed_rank_generate(compressed_rank_t * cr, cmph_uint32 * vals_table, cmph_uint32 n);
+
+cmph_uint32 compressed_rank_query(compressed_rank_t * cr, cmph_uint32 idx);
+
+cmph_uint32 compressed_rank_get_space_usage(compressed_rank_t * cr);
+
+void compressed_rank_dump(compressed_rank_t * cr, char **buf, cmph_uint32 *buflen);
+
+void compressed_rank_load(compressed_rank_t * cr, const char *buf, cmph_uint32 buflen);
+
+
+/** \fn void compressed_rank_pack(compressed_rank_t *cr, void *cr_packed);
+ *  \brief Support the ability to pack a compressed_rank structure into a preallocated contiguous memory space pointed by cr_packed.
+ *  \param cr points to the compressed_rank structure
+ *  \param cr_packed pointer to the contiguous memory area used to store the compressed_rank structure. The size of cr_packed must be at least @see compressed_rank_packed_size 
+ */
+void compressed_rank_pack(compressed_rank_t *cr, void *cr_packed);
+
+/** \fn cmph_uint32 compressed_rank_packed_size(compressed_rank_t *cr);
+ *  \brief Return the amount of space needed to pack a compressed_rank structure.
+ *  \return the size of the packed compressed_rank structure or zero for failures
+ */ 
+cmph_uint32 compressed_rank_packed_size(compressed_rank_t *cr);
+
+
+/** \fn cmph_uint32 compressed_rank_query_packed(void * cr_packed, cmph_uint32 idx);
+ *  \param cr_packed is a pointer to a contiguous memory area
+ *  \param idx is an index to compute the rank
+ *  \return an integer that represents the compressed_rank value.
+ */
+cmph_uint32 compressed_rank_query_packed(void * cr_packed, cmph_uint32 idx);
+
+#endif
diff --git a/girepository/cmph/compressed_seq.c b/girepository/cmph/compressed_seq.c
new file mode 100644
index 0000000..e558196
--- /dev/null
+++ b/girepository/cmph/compressed_seq.c
@@ -0,0 +1,378 @@
+#include "compressed_seq.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <limits.h>
+#include <string.h>
+
+#include "bitbool.h"
+
+// #define DEBUG
+#include "debug.h"
+
+static inline cmph_uint32 compressed_seq_i_log2(cmph_uint32 x)
+{
+	register cmph_uint32 res = 0;
+	
+	while(x > 1)
+	{
+		x >>= 1;
+		res++;
+	}
+	return res;
+};
+
+void compressed_seq_init(compressed_seq_t * cs)
+{
+	select_init(&cs->sel);
+	cs->n = 0;
+	cs->rem_r = 0;
+	cs->length_rems = 0;
+	cs->total_length = 0;
+	cs->store_table = 0;
+}
+
+void compressed_seq_destroy(compressed_seq_t * cs)
+{
+	free(cs->store_table);
+	cs->store_table = 0;
+	free(cs->length_rems);
+	cs->length_rems = 0;
+	select_destroy(&cs->sel);
+};
+
+
+void compressed_seq_generate(compressed_seq_t * cs, cmph_uint32 * vals_table, cmph_uint32 n)
+{
+	register cmph_uint32 i;
+	// lengths: represents lengths of encoded values	
+	register cmph_uint32 * lengths = (cmph_uint32 *)calloc(n, sizeof(cmph_uint32));
+	register cmph_uint32 rems_mask;
+	register cmph_uint32 stored_value;
+	
+	cs->n = n;
+	cs->total_length = 0;
+	
+	for(i = 0; i < cs->n; i++)
+	{
+		if(vals_table[i] == 0)
+		{
+			lengths[i] = 0;
+		}
+		else
+		{
+			lengths[i] = compressed_seq_i_log2(vals_table[i] + 1);
+			cs->total_length += lengths[i];
+		};
+	};
+	
+	if(cs->store_table)
+	{
+		free(cs->store_table);
+	}
+	cs->store_table = (cmph_uint32 *) calloc(((cs->total_length + 31) >> 5), sizeof(cmph_uint32));
+	cs->total_length = 0;
+	
+	for(i = 0; i < cs->n; i++)
+	{
+		if(vals_table[i] == 0)
+			continue;
+		stored_value = vals_table[i] - ((1U << lengths[i]) - 1U);
+		set_bits_at_pos(cs->store_table, cs->total_length, stored_value, lengths[i]);
+		cs->total_length += lengths[i];
+	};
+	
+	cs->rem_r = compressed_seq_i_log2(cs->total_length/cs->n);
+	
+	if(cs->rem_r == 0)
+	{
+		cs->rem_r = 1;
+	}
+	
+	if(cs->length_rems)
+	{
+		free(cs->length_rems);
+	}
+	
+	cs->length_rems = (cmph_uint32 *) calloc(BITS_TABLE_SIZE(cs->n, cs->rem_r), sizeof(cmph_uint32));
+	
+	rems_mask = (1U << cs->rem_r) - 1U;
+	cs->total_length = 0;
+	
+	for(i = 0; i < cs->n; i++)
+	{
+		cs->total_length += lengths[i];
+		set_bits_value(cs->length_rems, i, cs->total_length & rems_mask, cs->rem_r, rems_mask);
+		lengths[i] = cs->total_length >> cs->rem_r;
+	};
+	
+	select_init(&cs->sel);
+	 
+	// FABIANO: before it was (cs->total_length >> cs->rem_r) + 1. But I wiped out the + 1 because
+	// I changed the select structure to work up to m, instead of up to m - 1.
+	select_generate(&cs->sel, lengths, cs->n, (cs->total_length >> cs->rem_r));
+	
+	free(lengths);
+};
+
+cmph_uint32 compressed_seq_get_space_usage(compressed_seq_t * cs)
+{
+	register cmph_uint32 space_usage = select_get_space_usage(&cs->sel);
+	space_usage += ((cs->total_length + 31) >> 5) * (cmph_uint32)sizeof(cmph_uint32) * 8;
+	space_usage += BITS_TABLE_SIZE(cs->n, cs->rem_r) * (cmph_uint32)sizeof(cmph_uint32) * 8;
+	return  4 * (cmph_uint32)sizeof(cmph_uint32) * 8 + space_usage;
+}
+
+cmph_uint32 compressed_seq_query(compressed_seq_t * cs, cmph_uint32 idx)
+{
+	register cmph_uint32 enc_idx, enc_length;
+	register cmph_uint32 rems_mask;
+	register cmph_uint32 stored_value;
+	register cmph_uint32 sel_res;
+
+	assert(idx < cs->n); // FABIANO ADDED
+
+	rems_mask = (1U << cs->rem_r) - 1U;
+	
+	if(idx == 0)
+	{
+		enc_idx = 0;
+		sel_res = select_query(&cs->sel, idx);
+	}
+	else
+	{
+		sel_res = select_query(&cs->sel, idx - 1);
+		
+		enc_idx = (sel_res - (idx - 1)) << cs->rem_r;
+		enc_idx += get_bits_value(cs->length_rems, idx-1, cs->rem_r, rems_mask);
+		
+		sel_res = select_next_query(&cs->sel, sel_res);
+	};
+
+	enc_length = (sel_res - idx) << cs->rem_r;
+	enc_length += get_bits_value(cs->length_rems, idx, cs->rem_r, rems_mask);
+	enc_length -= enc_idx;
+	if(enc_length == 0)
+		return 0;
+		
+	stored_value = get_bits_at_pos(cs->store_table, enc_idx, enc_length);
+	return stored_value + ((1U << enc_length) - 1U);
+};
+
+void compressed_seq_dump(compressed_seq_t * cs, char ** buf, cmph_uint32 * buflen)
+{
+	register cmph_uint32 sel_size = select_packed_size(&(cs->sel));
+	register cmph_uint32 length_rems_size = BITS_TABLE_SIZE(cs->n, cs->rem_r) * 4;
+	register cmph_uint32 store_table_size = ((cs->total_length + 31) >> 5) * 4;
+	register cmph_uint32 pos = 0;
+	char * buf_sel = 0;
+	cmph_uint32 buflen_sel = 0;
+	
+	*buflen = 4*(cmph_uint32)sizeof(cmph_uint32) + sel_size +  length_rems_size + store_table_size;
+	
+	DEBUGP("sel_size = %u\n", sel_size);
+	DEBUGP("length_rems_size = %u\n", length_rems_size);
+	DEBUGP("store_table_size = %u\n", store_table_size);
+	*buf = (char *)calloc(*buflen, sizeof(char));
+	
+	if (!*buf) 
+	{
+		*buflen = UINT_MAX;
+		return;
+	}
+	
+	// dumping n, rem_r and total_length
+	memcpy(*buf, &(cs->n), sizeof(cmph_uint32));
+	pos += (cmph_uint32)sizeof(cmph_uint32);
+	DEBUGP("n = %u\n", cs->n);
+	
+	memcpy(*buf + pos, &(cs->rem_r), sizeof(cmph_uint32));
+	pos += (cmph_uint32)sizeof(cmph_uint32);
+	DEBUGP("rem_r = %u\n", cs->rem_r);
+
+	memcpy(*buf + pos, &(cs->total_length), sizeof(cmph_uint32));
+	pos += (cmph_uint32)sizeof(cmph_uint32);
+	DEBUGP("total_length = %u\n", cs->total_length);
+
+	
+	// dumping sel
+	select_dump(&cs->sel, &buf_sel, &buflen_sel);
+	memcpy(*buf + pos, &buflen_sel, sizeof(cmph_uint32));
+	pos += (cmph_uint32)sizeof(cmph_uint32);
+	DEBUGP("buflen_sel = %u\n", buflen_sel);
+
+	memcpy(*buf + pos, buf_sel, buflen_sel);
+	#ifdef DEBUG	
+	cmph_uint32 i = 0; 
+	for(i = 0; i < buflen_sel; i++)
+	{
+	    DEBUGP("pos = %u  -- buf_sel[%u] = %u\n", pos, i, *(*buf + pos + i));
+	}
+	#endif
+	pos += buflen_sel;
+	
+	free(buf_sel);
+	
+	// dumping length_rems
+	memcpy(*buf + pos, cs->length_rems, length_rems_size);
+	#ifdef DEBUG	
+	for(i = 0; i < length_rems_size; i++)
+	{
+	    DEBUGP("pos = %u -- length_rems_size = %u  -- length_rems[%u] = %u\n", pos, length_rems_size, i, *(*buf + pos + i));
+	}
+	#endif
+	pos += length_rems_size;
+
+	// dumping store_table
+	memcpy(*buf + pos, cs->store_table, store_table_size);
+
+	#ifdef DEBUG	
+	for(i = 0; i < store_table_size; i++)
+	{
+	    DEBUGP("pos = %u -- store_table_size = %u  -- store_table[%u] = %u\n", pos, store_table_size, i, *(*buf + pos + i));
+	}
+	#endif
+	DEBUGP("Dumped compressed sequence structure with size %u bytes\n", *buflen);
+}
+
+void compressed_seq_load(compressed_seq_t * cs, const char * buf, cmph_uint32 buflen)
+{
+	register cmph_uint32 pos = 0;
+	cmph_uint32 buflen_sel = 0;
+	register cmph_uint32 length_rems_size = 0;
+	register cmph_uint32 store_table_size = 0;
+	
+	// loading n, rem_r and total_length
+	memcpy(&(cs->n), buf, sizeof(cmph_uint32));
+	pos += (cmph_uint32)sizeof(cmph_uint32);
+	DEBUGP("n = %u\n", cs->n);
+
+	memcpy(&(cs->rem_r), buf + pos, sizeof(cmph_uint32));
+	pos += (cmph_uint32)sizeof(cmph_uint32);
+	DEBUGP("rem_r = %u\n", cs->rem_r);
+
+	memcpy(&(cs->total_length), buf + pos, sizeof(cmph_uint32));
+	pos += (cmph_uint32)sizeof(cmph_uint32);
+	DEBUGP("total_length = %u\n", cs->total_length);
+	
+	// loading sel
+	memcpy(&buflen_sel, buf + pos, sizeof(cmph_uint32));
+	pos += (cmph_uint32)sizeof(cmph_uint32);
+	DEBUGP("buflen_sel = %u\n", buflen_sel);
+
+	select_load(&cs->sel, buf + pos, buflen_sel);
+	#ifdef DEBUG	
+	cmph_uint32 i = 0;  
+	for(i = 0; i < buflen_sel; i++)
+	{
+	    DEBUGP("pos = %u  -- buf_sel[%u] = %u\n", pos, i, *(buf + pos + i));
+	}
+	#endif
+	pos += buflen_sel;
+	
+	// loading length_rems
+	if(cs->length_rems)
+	{
+		free(cs->length_rems);
+	}
+	length_rems_size = BITS_TABLE_SIZE(cs->n, cs->rem_r);
+	cs->length_rems = (cmph_uint32 *) calloc(length_rems_size, sizeof(cmph_uint32));
+	length_rems_size *= 4;
+	memcpy(cs->length_rems, buf + pos, length_rems_size);
+	
+	#ifdef DEBUG	
+	for(i = 0; i < length_rems_size; i++)
+	{
+	    DEBUGP("pos = %u -- length_rems_size = %u  -- length_rems[%u] = %u\n", pos, length_rems_size, i, *(buf + pos + i));
+	}
+	#endif
+	pos += length_rems_size;
+
+	// loading store_table
+	store_table_size = ((cs->total_length + 31) >> 5);
+	if(cs->store_table)
+	{
+		free(cs->store_table);
+	}
+	cs->store_table = (cmph_uint32 *) calloc(store_table_size, sizeof(cmph_uint32));
+        store_table_size *= 4;
+	memcpy(cs->store_table, buf + pos, store_table_size);
+	
+	#ifdef DEBUG	
+	for(i = 0; i < store_table_size; i++)
+	{
+	    DEBUGP("pos = %u -- store_table_size = %u  -- store_table[%u] = %u\n", pos, store_table_size, i, *(buf + pos + i));
+	}
+	#endif
+
+	DEBUGP("Loaded compressed sequence structure with size %u bytes\n", buflen);
+}
+
+void compressed_seq_pack(compressed_seq_t *cs, void *cs_packed)
+{
+	if (cs && cs_packed)
+	{
+		char *buf = NULL;
+		cmph_uint32 buflen = 0;
+		compressed_seq_dump(cs, &buf, &buflen);
+		memcpy(cs_packed, buf, buflen);
+		free(buf);
+	}
+
+}
+
+cmph_uint32 compressed_seq_packed_size(compressed_seq_t *cs)
+{
+	register cmph_uint32 sel_size = select_packed_size(&cs->sel);
+	register cmph_uint32 store_table_size = ((cs->total_length + 31) >> 5) * (cmph_uint32)sizeof(cmph_uint32);
+	register cmph_uint32 length_rems_size = BITS_TABLE_SIZE(cs->n, cs->rem_r) * (cmph_uint32)sizeof(cmph_uint32);
+	return 4 * (cmph_uint32)sizeof(cmph_uint32) + sel_size + store_table_size + length_rems_size;
+}
+
+
+cmph_uint32 compressed_seq_query_packed(void * cs_packed, cmph_uint32 idx)
+{
+	// unpacking cs_packed
+	register cmph_uint32 *ptr = (cmph_uint32 *)cs_packed;
+	register cmph_uint32 n = *ptr++;
+	register cmph_uint32 rem_r = *ptr++;
+	ptr++; // skipping total_length 
+// 	register cmph_uint32 total_length = *ptr++;
+	register cmph_uint32 buflen_sel = *ptr++;
+	register cmph_uint32 * sel_packed = ptr;
+	register cmph_uint32 * length_rems = (ptr += (buflen_sel >> 2)); 
+	register cmph_uint32 length_rems_size = BITS_TABLE_SIZE(n, rem_r);
+	register cmph_uint32 * store_table = (ptr += length_rems_size);
+
+	// compressed sequence query computation
+	register cmph_uint32 enc_idx, enc_length;
+	register cmph_uint32 rems_mask;
+	register cmph_uint32 stored_value;
+	register cmph_uint32 sel_res;
+
+	rems_mask = (1U << rem_r) - 1U;
+	
+	if(idx == 0)
+	{
+		enc_idx = 0;
+		sel_res = select_query_packed(sel_packed, idx);
+	}
+	else
+	{
+		sel_res = select_query_packed(sel_packed, idx - 1);
+		
+		enc_idx = (sel_res - (idx - 1)) << rem_r;
+		enc_idx += get_bits_value(length_rems, idx-1, rem_r, rems_mask);
+		
+		sel_res = select_next_query_packed(sel_packed, sel_res);
+	};
+
+	enc_length = (sel_res - idx) << rem_r;
+	enc_length += get_bits_value(length_rems, idx, rem_r, rems_mask);
+	enc_length -= enc_idx;
+	if(enc_length == 0)
+		return 0;
+		
+	stored_value = get_bits_at_pos(store_table, enc_idx, enc_length);
+	return stored_value + ((1U << enc_length) - 1U);
+}
diff --git a/girepository/cmph/compressed_seq.h b/girepository/cmph/compressed_seq.h
new file mode 100644
index 0000000..8d87fc7
--- /dev/null
+++ b/girepository/cmph/compressed_seq.h
@@ -0,0 +1,84 @@
+#ifndef __CMPH_COMPRESSED_SEQ_H__
+#define __CMPH_COMPRESSED_SEQ_H__
+
+#include"select.h"
+
+struct _compressed_seq_t
+{
+	cmph_uint32 n; // number of values stored in store_table
+	// The length in bits of each value is decomposed into two compnents: the lg(n) MSBs are stored in rank_select data structure
+	// the remaining LSBs are stored in a table of n cells, each one of rem_r bits.
+	cmph_uint32 rem_r;
+	cmph_uint32 total_length; // total length in bits of stored_table
+	select_t sel;
+	cmph_uint32 * length_rems;
+	cmph_uint32 * store_table;
+};
+
+typedef struct _compressed_seq_t compressed_seq_t;
+
+/** \fn void compressed_seq_init(compressed_seq_t * cs);
+ *  \brief Initialize a compressed sequence structure.
+ *  \param cs points to the compressed sequence structure to be initialized
+ */
+void compressed_seq_init(compressed_seq_t * cs);
+
+/** \fn void compressed_seq_destroy(compressed_seq_t * cs);
+ *  \brief Destroy a compressed sequence given as input.
+ *  \param cs points to the compressed sequence structure to be destroyed
+ */
+void compressed_seq_destroy(compressed_seq_t * cs);
+
+/** \fn void compressed_seq_generate(compressed_seq_t * cs, cmph_uint32 * vals_table, cmph_uint32 n);
+ *  \brief Generate a compressed sequence from an input array with n values.
+ *  \param cs points to the compressed sequence structure
+ *  \param vals_table poiter to the array given as input
+ *  \param n number of values in @see vals_table
+ */
+void compressed_seq_generate(compressed_seq_t * cs, cmph_uint32 * vals_table, cmph_uint32 n);
+
+
+/** \fn cmph_uint32 compressed_seq_query(compressed_seq_t * cs, cmph_uint32 idx);
+ *  \brief Returns the value stored at index @see idx of the compressed sequence structure.
+ *  \param cs points to the compressed sequence structure
+ *  \param idx index to retrieve the value from
+ *  \return the value stored at index @see idx of the compressed sequence structure
+ */
+cmph_uint32 compressed_seq_query(compressed_seq_t * cs, cmph_uint32 idx);
+
+
+/** \fn cmph_uint32 compressed_seq_get_space_usage(compressed_seq_t * cs);
+ *  \brief Returns amount of space (in bits) to store the compressed sequence.
+ *  \param cs points to the compressed sequence structure
+ *  \return the amount of space (in bits) to store @see cs
+ */
+cmph_uint32 compressed_seq_get_space_usage(compressed_seq_t * cs);
+
+void compressed_seq_dump(compressed_seq_t * cs, char ** buf, cmph_uint32 * buflen);
+
+void compressed_seq_load(compressed_seq_t * cs, const char * buf, cmph_uint32 buflen);
+
+
+/** \fn void compressed_seq_pack(compressed_seq_t *cs, void *cs_packed);
+ *  \brief Support the ability to pack a compressed sequence structure into a preallocated contiguous memory space pointed by cs_packed.
+ *  \param cs points to the compressed sequence structure
+ *  \param cs_packed pointer to the contiguous memory area used to store the compressed sequence structure. The size of cs_packed must be at least @see compressed_seq_packed_size 
+ */
+void compressed_seq_pack(compressed_seq_t *cs, void *cs_packed);
+
+/** \fn cmph_uint32 compressed_seq_packed_size(compressed_seq_t *cs);
+ *  \brief Return the amount of space needed to pack a compressed sequence structure.
+ *  \return the size of the packed compressed sequence structure or zero for failures
+ */ 
+cmph_uint32 compressed_seq_packed_size(compressed_seq_t *cs);
+
+
+/** \fn cmph_uint32 compressed_seq_query_packed(void * cs_packed, cmph_uint32 idx);
+ *  \brief Returns the value stored at index @see idx of the packed compressed sequence structure.
+ *  \param cs_packed is a pointer to a contiguous memory area
+ *  \param idx is the index to retrieve the value from
+ *  \return the value stored at index @see idx of the packed compressed sequence structure
+ */
+cmph_uint32 compressed_seq_query_packed(void * cs_packed, cmph_uint32 idx);
+
+#endif
diff --git a/girepository/cmph/debug.h b/girepository/cmph/debug.h
new file mode 100644
index 0000000..0f7ddb1
--- /dev/null
+++ b/girepository/cmph/debug.h
@@ -0,0 +1,53 @@
+#ifdef DEBUGP
+#undef DEBUGP
+#endif
+
+#ifdef __cplusplus
+#include <cstdio>
+#ifdef WIN32
+#include <cstring>
+#endif
+#else
+#include <stdio.h>
+#ifdef WIN32
+#include <string.h>
+#endif
+#endif
+
+#ifndef __GNUC__
+#ifndef __DEBUG_H__
+#define __DEBUG_H__
+#include <stdarg.h>
+static void debugprintf(const char *format, ...)
+{
+    va_list ap;
+	char *f = NULL;
+	const char *p="%s:%d ";
+	size_t plen = strlen(p);
+    va_start(ap, format);
+	f = (char *)malloc(plen + strlen(format) + 1);
+	if (!f) return;
+	memcpy(f, p, plen);
+	memcpy(f + plen, format, strlen(format) + 1);
+    vfprintf(stderr, f, ap);
+    va_end(ap);
+	free(f);
+}
+static void dummyprintf(const char *format, ...)
+{}
+#endif
+#endif
+
+#ifdef DEBUG
+#ifndef __GNUC__
+#define DEBUGP debugprintf
+#else
+#define DEBUGP(args...) do { fprintf(stderr, "%s:%d ", __FILE__, __LINE__); fprintf(stderr, ## args); } while(0)
+#endif
+#else
+#ifndef __GNUC__
+#define DEBUGP dummyprintf
+#else
+#define DEBUGP(args...)
+#endif
+#endif
diff --git a/girepository/cmph/djb2_hash.c b/girepository/cmph/djb2_hash.c
new file mode 100644
index 0000000..d3b4330
--- /dev/null
+++ b/girepository/cmph/djb2_hash.c
@@ -0,0 +1,49 @@
+#include "djb2_hash.h"
+#include <stdlib.h>
+
+djb2_state_t *djb2_state_new()
+{
+	djb2_state_t *state = (djb2_state_t *)malloc(sizeof(djb2_state_t));
+	state->hashfunc = CMPH_HASH_DJB2;
+	return state;
+}
+
+void djb2_state_destroy(djb2_state_t *state)
+{
+	free(state);
+}
+
+cmph_uint32 djb2_hash(djb2_state_t *state, const char *k, cmph_uint32 keylen)
+{
+	register cmph_uint32 hash = 5381;
+	const unsigned char *ptr = (unsigned char *)k;
+	cmph_uint32 i = 0;
+	while (i < keylen) 
+	{
+		hash = hash*33 ^ *ptr;
+		++ptr, ++i;
+	}
+	return hash;
+}
+
+
+void djb2_state_dump(djb2_state_t *state, char **buf, cmph_uint32 *buflen)
+{
+	*buf = NULL;
+	*buflen = 0;
+	return;
+}
+
+djb2_state_t *djb2_state_copy(djb2_state_t *src_state)
+{
+	djb2_state_t *dest_state = (djb2_state_t *)malloc(sizeof(djb2_state_t));
+	dest_state->hashfunc = src_state->hashfunc;
+	return dest_state;
+}
+
+djb2_state_t *djb2_state_load(const char *buf, cmph_uint32 buflen)
+{
+	djb2_state_t *state = (djb2_state_t *)malloc(sizeof(djb2_state_t));
+	state->hashfunc = CMPH_HASH_DJB2;
+	return state;
+}
diff --git a/girepository/cmph/djb2_hash.h b/girepository/cmph/djb2_hash.h
new file mode 100644
index 0000000..dda97e3
--- /dev/null
+++ b/girepository/cmph/djb2_hash.h
@@ -0,0 +1,18 @@
+#ifndef __DJB2_HASH_H__
+#define __DJB2_HASH_H__
+
+#include "hash.h"
+
+typedef struct __djb2_state_t
+{
+	CMPH_HASH hashfunc;
+} djb2_state_t;
+
+djb2_state_t *djb2_state_new();
+cmph_uint32 djb2_hash(djb2_state_t *state, const char *k, cmph_uint32 keylen);
+void djb2_state_dump(djb2_state_t *state, char **buf, cmph_uint32 *buflen);
+djb2_state_t *djb2_state_copy(djb2_state_t *src_state);
+djb2_state_t *djb2_state_load(const char *buf, cmph_uint32 buflen);
+void djb2_state_destroy(djb2_state_t *state);
+
+#endif
diff --git a/girepository/cmph/fch.c b/girepository/cmph/fch.c
new file mode 100644
index 0000000..67b68fb
--- /dev/null
+++ b/girepository/cmph/fch.c
@@ -0,0 +1,517 @@
+#include "fch.h"
+#include "cmph_structs.h"
+#include "fch_structs.h"
+#include "hash.h"
+#include "bitbool.h"
+#include "fch_buckets.h"
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#define INDEX 0 /* alignment index within a bucket */
+//#define DEBUG
+#include "debug.h"
+
+static fch_buckets_t * mapping(cmph_config_t *mph);
+static cmph_uint32 * ordering(fch_buckets_t * buckets);
+static cmph_uint8 check_for_collisions_h2(fch_config_data_t *fch, fch_buckets_t * buckets, cmph_uint32 *sorted_indexes);
+static void permut(cmph_uint32 * vector, cmph_uint32 n);
+static cmph_uint8 searching(fch_config_data_t *fch, fch_buckets_t *buckets, cmph_uint32 *sorted_indexes);
+
+fch_config_data_t *fch_config_new()
+{
+	fch_config_data_t *fch;
+	fch = (fch_config_data_t *)malloc(sizeof(fch_config_data_t));
+	assert(fch);
+	memset(fch, 0, sizeof(fch_config_data_t));
+	fch->hashfuncs[0] = CMPH_HASH_JENKINS;
+	fch->hashfuncs[1] = CMPH_HASH_JENKINS;
+	fch->m = fch->b = 0;
+	fch->c = fch->p1 = fch->p2 = 0.0;
+	fch->g = NULL;
+	fch->h1 = NULL;
+	fch->h2 = NULL;
+	return fch;
+}
+
+void fch_config_destroy(cmph_config_t *mph)
+{
+	fch_config_data_t *data = (fch_config_data_t *)mph->data;
+	//DEBUGP("Destroying algorithm dependent data\n");
+	free(data);
+}
+
+void fch_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs)
+{
+	fch_config_data_t *fch = (fch_config_data_t *)mph->data;
+	CMPH_HASH *hashptr = hashfuncs;
+	cmph_uint32 i = 0;
+	while(*hashptr != CMPH_HASH_COUNT)
+	{
+		if (i >= 2) break; //fch only uses two hash functions
+		fch->hashfuncs[i] = *hashptr;	
+		++i, ++hashptr;
+	}
+}
+
+cmph_uint32 mixh10h11h12(cmph_uint32 b, double p1, double p2, cmph_uint32 initial_index)
+{
+	register cmph_uint32 int_p2 = (cmph_uint32)p2;
+	if (initial_index < p1)  initial_index %= int_p2;  /* h11 o h10 */
+	else { /* h12 o h10 */
+		initial_index %= b;
+		if(initial_index < p2) initial_index += int_p2;
+	}
+	return initial_index;
+}
+
+
+cmph_uint32 fch_calc_b(double c, cmph_uint32 m)
+{
+	return (cmph_uint32)ceil((c*m)/(log((double)m)/log(2.0) + 1));
+}
+
+double fch_calc_p1(cmph_uint32 m)
+{
+	return ceil(0.55*m);
+}
+
+double fch_calc_p2(cmph_uint32 b)
+{
+	return ceil(0.3*b);
+}
+
+static fch_buckets_t * mapping(cmph_config_t *mph)
+{
+	cmph_uint32 i = 0;
+	fch_buckets_t *buckets = NULL;
+	fch_config_data_t *fch = (fch_config_data_t *)mph->data;
+	if (fch->h1) hash_state_destroy(fch->h1);
+	fch->h1 = hash_state_new(fch->hashfuncs[0], fch->m);  
+	fch->b = fch_calc_b(fch->c, fch->m);
+	fch->p1 = fch_calc_p1(fch->m);
+	fch->p2 = fch_calc_p2(fch->b);
+	//DEBUGP("b:%u   p1:%f   p2:%f\n", fch->b, fch->p1, fch->p2);
+	buckets = fch_buckets_new(fch->b);
+
+	mph->key_source->rewind(mph->key_source->data);  
+	for(i = 0; i < fch->m; i++)
+	{
+		cmph_uint32 h1, keylen;
+		char *key = NULL;
+		mph->key_source->read(mph->key_source->data, &key, &keylen);	
+		h1 = hash(fch->h1, key, keylen) % fch->m;
+		h1 = mixh10h11h12 (fch->b, fch->p1, fch->p2, h1);
+		fch_buckets_insert(buckets, h1, key, keylen);
+		key = NULL; // transger memory ownership
+		
+	}
+	return buckets;  
+}
+
+
+// returns the buckets indexes sorted by their sizes. 
+static cmph_uint32 * ordering(fch_buckets_t * buckets)
+{
+  return fch_buckets_get_indexes_sorted_by_size(buckets);
+}
+
+/* Check whether function h2 causes collisions among the keys of each bucket */ 
+static cmph_uint8 check_for_collisions_h2(fch_config_data_t *fch, fch_buckets_t * buckets, cmph_uint32 *sorted_indexes)
+{
+	//cmph_uint32 max_size = fch_buckets_get_max_size(buckets);
+	cmph_uint8 * hashtable = (cmph_uint8 *)calloc((size_t)fch->m, sizeof(cmph_uint8));
+	cmph_uint32 nbuckets = fch_buckets_get_nbuckets(buckets);
+	cmph_uint32 i = 0, index = 0, j =0;
+	for (i = 0; i < nbuckets; i++)
+	{
+		cmph_uint32 nkeys = fch_buckets_get_size(buckets, sorted_indexes[i]);
+		memset(hashtable, 0, (size_t)fch->m);
+		//DEBUGP("bucket %u -- nkeys: %u\n", i, nkeys);
+		for (j = 0; j < nkeys; j++)
+		{
+			char * key = fch_buckets_get_key(buckets, sorted_indexes[i], j);
+			cmph_uint32 keylen = fch_buckets_get_keylength(buckets, sorted_indexes[i], j);
+			index = hash(fch->h2, key, keylen) % fch->m;
+			if(hashtable[index]) { // collision detected
+				free(hashtable);
+				return 1;
+			}
+			hashtable[index] = 1;
+		}
+	}
+	free(hashtable);
+	return 0;
+}
+
+static void permut(cmph_uint32 * vector, cmph_uint32 n)
+{ 
+  cmph_uint32 i, j, b;
+  for (i = 0; i < n; i++) {
+    j = (cmph_uint32) rand() % n;
+    b = vector[i];
+    vector[i] = vector[j];
+    vector[j] = b;
+  }
+}
+
+static cmph_uint8 searching(fch_config_data_t *fch, fch_buckets_t *buckets, cmph_uint32 *sorted_indexes)
+{
+	cmph_uint32 * random_table = (cmph_uint32 *) calloc((size_t)fch->m, sizeof(cmph_uint32));
+	cmph_uint32 * map_table    = (cmph_uint32 *) calloc((size_t)fch->m, sizeof(cmph_uint32));
+	cmph_uint32 iteration_to_generate_h2 = 0;
+	cmph_uint32 searching_iterations     = 0;
+	cmph_uint8 restart                   = 0;
+	cmph_uint32 nbuckets                 = fch_buckets_get_nbuckets(buckets);
+	cmph_uint32 i, j, z, counter = 0, filled_count = 0;
+	if (fch->g) free (fch->g);
+	fch->g = (cmph_uint32 *) calloc((size_t)fch->b, sizeof(cmph_uint32));
+
+	//DEBUGP("max bucket size: %u\n", fch_buckets_get_max_size(buckets));
+
+	for(i = 0; i < fch->m; i++)
+	{
+		random_table[i] = i;
+	}
+	permut(random_table, fch->m);
+	for(i = 0; i < fch->m; i++)
+	{
+		map_table[random_table[i]] = i;
+	}
+	do {   
+		if (fch->h2) hash_state_destroy(fch->h2);
+		fch->h2 = hash_state_new(fch->hashfuncs[1], fch->m);  
+		restart = check_for_collisions_h2(fch, buckets, sorted_indexes);
+		filled_count = 0;
+		if (!restart) 
+		{
+			searching_iterations++; iteration_to_generate_h2 = 0;
+			//DEBUGP("searching_iterations: %u\n", searching_iterations);
+		}
+		else {
+			iteration_to_generate_h2++;
+			//DEBUGP("iteration_to_generate_h2: %u\n", iteration_to_generate_h2);
+		}		
+		for(i = 0; (i < nbuckets) && !restart; i++) {
+			cmph_uint32 bucketsize = fch_buckets_get_size(buckets, sorted_indexes[i]);
+			if (bucketsize == 0)
+			{
+				restart = 0; // false
+				break;
+			}
+			else restart = 1; // true
+			for(z = 0; (z < (fch->m - filled_count)) && restart; z++) {
+				char * key = fch_buckets_get_key(buckets, sorted_indexes[i], INDEX);
+				cmph_uint32 keylen = fch_buckets_get_keylength(buckets, sorted_indexes[i], INDEX);
+				cmph_uint32 h2 = hash(fch->h2, key, keylen) % fch->m;				
+				counter = 0; 
+				restart = 0; // false
+				fch->g[sorted_indexes[i]] = (fch->m + random_table[filled_count + z] - h2) % fch->m;
+				//DEBUGP("g[%u]: %u\n", sorted_indexes[i], fch->g[sorted_indexes[i]]);
+				j = INDEX;
+				do {
+					cmph_uint32 index = 0;
+					key = fch_buckets_get_key(buckets, sorted_indexes[i], j);
+					keylen = fch_buckets_get_keylength(buckets, sorted_indexes[i], j);
+					h2 = hash(fch->h2, key, keylen) % fch->m;
+					index = (h2 + fch->g[sorted_indexes[i]]) % fch->m;
+					//DEBUGP("key:%s  keylen:%u  index: %u  h2:%u  bucketsize:%u\n", key, keylen, index, h2, bucketsize);
+					if (map_table[index] >= filled_count) {  
+						cmph_uint32 y  = map_table[index];
+						cmph_uint32 ry = random_table[y];
+						random_table[y] = random_table[filled_count];
+						random_table[filled_count] = ry;
+						map_table[random_table[y]] = y;
+						map_table[random_table[filled_count]] = filled_count;
+						filled_count++;
+						counter ++; 
+					}
+					else { 
+						restart = 1; // true
+						filled_count = filled_count - counter;
+						counter = 0; 
+						break;
+					}
+					j = (j + 1) % bucketsize;
+				} while(j % bucketsize != INDEX); 
+			}
+			//getchar();
+		}              
+	} while(restart  && (searching_iterations < 10) && (iteration_to_generate_h2 < 1000));
+	free(map_table);
+	free(random_table);
+	return restart;
+}
+
+
+
+cmph_t *fch_new(cmph_config_t *mph, double c)
+{
+	cmph_t *mphf = NULL;
+	fch_data_t *fchf = NULL;
+	cmph_uint32 iterations = 100;
+	cmph_uint8 restart_mapping = 0;
+	fch_buckets_t * buckets = NULL;
+	cmph_uint32 * sorted_indexes = NULL;
+	fch_config_data_t *fch = (fch_config_data_t *)mph->data;
+	fch->m = mph->key_source->nkeys;
+	//DEBUGP("m: %f\n", fch->m);
+	if (c <= 2) c = 2.6; // validating restrictions over parameter c.
+	fch->c = c;
+	//DEBUGP("c: %f\n", fch->c);
+	fch->h1 = NULL;
+	fch->h2 = NULL;
+	fch->g = NULL;
+	do
+	{	  
+		if (mph->verbosity)
+		{
+			fprintf(stderr, "Entering mapping step for mph creation of %u keys\n", fch->m);
+		}
+		if (buckets) fch_buckets_destroy(buckets);
+		buckets = mapping(mph);
+		if (mph->verbosity)
+		{
+			fprintf(stderr, "Starting ordering step\n");
+		}
+		if (sorted_indexes) free (sorted_indexes);
+		sorted_indexes = ordering(buckets);
+		if (mph->verbosity)
+		{
+			fprintf(stderr, "Starting searching step.\n");
+		}
+		restart_mapping = searching(fch, buckets, sorted_indexes);
+		iterations--;
+		
+        } while(restart_mapping && iterations > 0);
+	if (buckets) fch_buckets_destroy(buckets);
+	if (sorted_indexes) free (sorted_indexes);
+	if (iterations == 0) return NULL;
+	mphf = (cmph_t *)malloc(sizeof(cmph_t));
+	mphf->algo = mph->algo;
+	fchf = (fch_data_t *)malloc(sizeof(fch_data_t));
+	fchf->g = fch->g;
+	fch->g = NULL; //transfer memory ownership
+	fchf->h1 = fch->h1;
+	fch->h1 = NULL; //transfer memory ownership
+	fchf->h2 = fch->h2;
+	fch->h2 = NULL; //transfer memory ownership
+	fchf->p2 = fch->p2;
+	fchf->p1 = fch->p1;
+	fchf->b = fch->b;
+	fchf->c = fch->c;
+	fchf->m = fch->m;
+	mphf->data = fchf;
+	mphf->size = fch->m;
+	//DEBUGP("Successfully generated minimal perfect hash\n");
+	if (mph->verbosity)
+	{
+		fprintf(stderr, "Successfully generated minimal perfect hash function\n");
+	}
+	return mphf;
+}
+
+int fch_dump(cmph_t *mphf, FILE *fd)
+{
+	char *buf = NULL;
+	cmph_uint32 buflen;
+	register size_t nbytes;
+	
+	fch_data_t *data = (fch_data_t *)mphf->data;
+	__cmph_dump(mphf, fd);
+
+	hash_state_dump(data->h1, &buf, &buflen);
+	//DEBUGP("Dumping hash state with %u bytes to disk\n", buflen);
+	nbytes = fwrite(&buflen, sizeof(cmph_uint32), (size_t)1, fd);
+	nbytes = fwrite(buf, (size_t)buflen, (size_t)1, fd);
+	free(buf);
+
+	hash_state_dump(data->h2, &buf, &buflen);
+	//DEBUGP("Dumping hash state with %u bytes to disk\n", buflen);
+	nbytes = fwrite(&buflen, sizeof(cmph_uint32), (size_t)1, fd);
+	nbytes = fwrite(buf, (size_t)buflen, (size_t)1, fd);
+	free(buf);
+
+	nbytes = fwrite(&(data->m), sizeof(cmph_uint32), (size_t)1, fd);
+	nbytes = fwrite(&(data->c), sizeof(double), (size_t)1, fd);
+	nbytes = fwrite(&(data->b), sizeof(cmph_uint32), (size_t)1, fd);
+	nbytes = fwrite(&(data->p1), sizeof(double), (size_t)1, fd);
+	nbytes = fwrite(&(data->p2), sizeof(double), (size_t)1, fd);
+	nbytes = fwrite(data->g, sizeof(cmph_uint32)*(data->b), (size_t)1, fd);
+	#ifdef DEBUG
+	cmph_uint32 i;
+	fprintf(stderr, "G: ");
+	for (i = 0; i < data->b; ++i) fprintf(stderr, "%u ", data->g[i]);
+	fprintf(stderr, "\n");
+	#endif
+	return 1;
+}
+
+void fch_load(FILE *f, cmph_t *mphf)
+{
+	char *buf = NULL;
+	cmph_uint32 buflen;
+	register size_t nbytes;
+	fch_data_t *fch = (fch_data_t *)malloc(sizeof(fch_data_t));
+
+	//DEBUGP("Loading fch mphf\n");
+	mphf->data = fch;
+	//DEBUGP("Reading h1\n");
+	fch->h1 = NULL;
+	nbytes = fread(&buflen, sizeof(cmph_uint32), (size_t)1, f);
+	//DEBUGP("Hash state of h1 has %u bytes\n", buflen);
+	buf = (char *)malloc((size_t)buflen);
+	nbytes = fread(buf, (size_t)buflen, (size_t)1, f);
+	fch->h1 = hash_state_load(buf, buflen);
+	free(buf);
+	
+	//DEBUGP("Loading fch mphf\n");
+	mphf->data = fch;
+	//DEBUGP("Reading h2\n");
+	fch->h2 = NULL;
+	nbytes = fread(&buflen, sizeof(cmph_uint32), (size_t)1, f);
+	//DEBUGP("Hash state of h2 has %u bytes\n", buflen);
+	buf = (char *)malloc((size_t)buflen);
+	nbytes = fread(buf, (size_t)buflen, (size_t)1, f);
+	fch->h2 = hash_state_load(buf, buflen);
+	free(buf);
+	
+	
+	//DEBUGP("Reading m and n\n");
+	nbytes = fread(&(fch->m), sizeof(cmph_uint32), (size_t)1, f);
+	nbytes = fread(&(fch->c), sizeof(double), (size_t)1, f);
+	nbytes = fread(&(fch->b), sizeof(cmph_uint32), (size_t)1, f);
+	nbytes = fread(&(fch->p1), sizeof(double), (size_t)1, f);
+	nbytes = fread(&(fch->p2), sizeof(double), (size_t)1, f);
+
+	fch->g = (cmph_uint32 *)malloc(sizeof(cmph_uint32)*fch->b);
+	nbytes = fread(fch->g, fch->b*sizeof(cmph_uint32), (size_t)1, f);
+	#ifdef DEBUG
+	cmph_uint32 i;
+	fprintf(stderr, "G: ");
+	for (i = 0; i < fch->b; ++i) fprintf(stderr, "%u ", fch->g[i]);
+	fprintf(stderr, "\n");
+	#endif
+	return;
+}
+
+cmph_uint32 fch_search(cmph_t *mphf, const char *key, cmph_uint32 keylen)
+{
+	fch_data_t *fch = mphf->data;
+	cmph_uint32 h1 = hash(fch->h1, key, keylen) % fch->m;
+	cmph_uint32 h2 = hash(fch->h2, key, keylen) % fch->m;
+	h1 = mixh10h11h12 (fch->b, fch->p1, fch->p2, h1);
+	//DEBUGP("key: %s h1: %u h2: %u  g[h1]: %u\n", key, h1, h2, fch->g[h1]);
+	return (h2 + fch->g[h1]) % fch->m;
+}
+void fch_destroy(cmph_t *mphf)
+{
+	fch_data_t *data = (fch_data_t *)mphf->data;
+	free(data->g);
+	hash_state_destroy(data->h1);
+	hash_state_destroy(data->h2);
+	free(data);
+	free(mphf);
+}
+
+/** \fn void fch_pack(cmph_t *mphf, void *packed_mphf);
+ *  \brief Support the ability to pack a perfect hash function into a preallocated contiguous memory space pointed by packed_mphf.
+ *  \param mphf pointer to the resulting mphf
+ *  \param packed_mphf pointer to the contiguous memory area used to store the resulting mphf. The size of packed_mphf must be at least cmph_packed_size() 
+ */
+void fch_pack(cmph_t *mphf, void *packed_mphf)
+{
+	fch_data_t *data = (fch_data_t *)mphf->data;
+	cmph_uint8 * ptr = packed_mphf;
+
+	// packing h1 type
+	CMPH_HASH h1_type = hash_get_type(data->h1);
+	*((cmph_uint32 *) ptr) = h1_type;
+	ptr += sizeof(cmph_uint32);
+
+	// packing h1
+	hash_state_pack(data->h1, ptr);
+	ptr += hash_state_packed_size(h1_type);
+
+	// packing h2 type
+	CMPH_HASH h2_type = hash_get_type(data->h2);
+	*((cmph_uint32 *) ptr) = h2_type;
+	ptr += sizeof(cmph_uint32);
+
+	// packing h2
+	hash_state_pack(data->h2, ptr);
+	ptr += hash_state_packed_size(h2_type);
+
+	// packing m
+	*((cmph_uint32 *) ptr) = data->m;
+	ptr += sizeof(data->m);
+
+	// packing b
+	*((cmph_uint32 *) ptr) = data->b;
+	ptr += sizeof(data->b);
+	
+	// packing p1
+	*((cmph_uint64 *)ptr) = (cmph_uint64)data->p1; 
+	ptr += sizeof(data->p1);
+
+	// packing p2
+	*((cmph_uint64 *)ptr) = (cmph_uint64)data->p2; 
+	ptr += sizeof(data->p2);
+
+	// packing g
+	memcpy(ptr, data->g, sizeof(cmph_uint32)*(data->b));	
+}
+
+/** \fn cmph_uint32 fch_packed_size(cmph_t *mphf);
+ *  \brief Return the amount of space needed to pack mphf.
+ *  \param mphf pointer to a mphf
+ *  \return the size of the packed function or zero for failures
+ */ 
+cmph_uint32 fch_packed_size(cmph_t *mphf)
+{
+	fch_data_t *data = (fch_data_t *)mphf->data;
+	CMPH_HASH h1_type = hash_get_type(data->h1); 
+	CMPH_HASH h2_type = hash_get_type(data->h2); 
+
+	return (cmph_uint32)(sizeof(CMPH_ALGO) + hash_state_packed_size(h1_type) + hash_state_packed_size(h2_type) + 
+			4*sizeof(cmph_uint32) + 2*sizeof(double) + sizeof(cmph_uint32)*(data->b));
+}
+
+
+/** cmph_uint32 fch_search(void *packed_mphf, const char *key, cmph_uint32 keylen);
+ *  \brief Use the packed mphf to do a search. 
+ *  \param  packed_mphf pointer to the packed mphf
+ *  \param key key to be hashed
+ *  \param keylen key legth in bytes
+ *  \return The mphf value
+ */
+cmph_uint32 fch_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen)
+{
+	register cmph_uint8 *h1_ptr = packed_mphf;
+	register CMPH_HASH h1_type  = *((cmph_uint32 *)h1_ptr);
+	h1_ptr += 4;
+
+	register cmph_uint8 *h2_ptr = h1_ptr + hash_state_packed_size(h1_type);
+	register CMPH_HASH h2_type  = *((cmph_uint32 *)h2_ptr);
+	h2_ptr += 4;
+	
+	register cmph_uint32 *g_ptr = (cmph_uint32 *)(h2_ptr + hash_state_packed_size(h2_type));
+	
+	register cmph_uint32 m = *g_ptr++;  
+
+	register cmph_uint32 b = *g_ptr++;  
+
+	register double p1 = (double)(*((cmph_uint64 *)g_ptr));
+	g_ptr += 2;
+
+	register double p2 = (double)(*((cmph_uint64 *)g_ptr));
+	g_ptr += 2;
+
+	register cmph_uint32 h1 = hash_packed(h1_ptr, h1_type, key, keylen) % m; 
+	register cmph_uint32 h2 = hash_packed(h2_ptr, h2_type, key, keylen) % m;
+
+	h1 = mixh10h11h12 (b, p1, p2, h1);
+	return (h2 + g_ptr[h1]) % m;
+}
+
diff --git a/girepository/cmph/fch.h b/girepository/cmph/fch.h
new file mode 100644
index 0000000..ec4f0f5
--- /dev/null
+++ b/girepository/cmph/fch.h
@@ -0,0 +1,48 @@
+#ifndef __CMPH_FCH_H__
+#define __CMPH_FCH_H__
+
+#include "cmph.h"
+
+typedef struct __fch_data_t fch_data_t;
+typedef struct __fch_config_data_t fch_config_data_t;
+
+/* Parameters calculation */
+cmph_uint32 fch_calc_b(double c, cmph_uint32 m);
+double fch_calc_p1(cmph_uint32 m);
+double fch_calc_p2(cmph_uint32 b);
+cmph_uint32 mixh10h11h12(cmph_uint32 b, double p1, double p2, cmph_uint32 initial_index);
+
+fch_config_data_t *fch_config_new();
+void fch_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs);
+void fch_config_destroy(cmph_config_t *mph);
+cmph_t *fch_new(cmph_config_t *mph, double c);
+
+void fch_load(FILE *f, cmph_t *mphf);
+int fch_dump(cmph_t *mphf, FILE *f);
+void fch_destroy(cmph_t *mphf);
+cmph_uint32 fch_search(cmph_t *mphf, const char *key, cmph_uint32 keylen);
+
+/** \fn void fch_pack(cmph_t *mphf, void *packed_mphf);
+ *  \brief Support the ability to pack a perfect hash function into a preallocated contiguous memory space pointed by packed_mphf.
+ *  \param mphf pointer to the resulting mphf
+ *  \param packed_mphf pointer to the contiguous memory area used to store the resulting mphf. The size of packed_mphf must be at least cmph_packed_size() 
+ */
+void fch_pack(cmph_t *mphf, void *packed_mphf);
+
+/** \fn cmph_uint32 fch_packed_size(cmph_t *mphf);
+ *  \brief Return the amount of space needed to pack mphf.
+ *  \param mphf pointer to a mphf
+ *  \return the size of the packed function or zero for failures
+ */ 
+cmph_uint32 fch_packed_size(cmph_t *mphf);
+
+/** cmph_uint32 fch_search(void *packed_mphf, const char *key, cmph_uint32 keylen);
+ *  \brief Use the packed mphf to do a search. 
+ *  \param  packed_mphf pointer to the packed mphf
+ *  \param key key to be hashed
+ *  \param keylen key legth in bytes
+ *  \return The mphf value
+ */
+cmph_uint32 fch_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen);
+
+#endif
diff --git a/girepository/cmph/fch_buckets.c b/girepository/cmph/fch_buckets.c
new file mode 100644
index 0000000..24b98e6
--- /dev/null
+++ b/girepository/cmph/fch_buckets.c
@@ -0,0 +1,214 @@
+#include "vqueue.h"
+#include "fch_buckets.h"
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+//#define DEBUG
+#include "debug.h"
+
+typedef struct __fch_bucket_entry_t
+{
+  char * value;
+  cmph_uint32 length;
+} fch_bucket_entry_t;
+
+typedef struct __fch_bucket_t
+{
+  fch_bucket_entry_t * entries;
+  cmph_uint32 capacity, size;
+} fch_bucket_t;
+
+
+
+static void fch_bucket_new(fch_bucket_t *bucket) 
+{
+	assert(bucket);
+	bucket->size = 0;
+	bucket->entries = NULL;
+	bucket->capacity = 0;
+}
+
+static void fch_bucket_destroy(fch_bucket_t *bucket)
+{
+	cmph_uint32 i;
+	assert(bucket);
+	for (i = 0; i < bucket->size; i++)
+	{
+		free((bucket->entries + i)->value);
+	}
+	free(bucket->entries);
+}
+
+
+static void fch_bucket_reserve(fch_bucket_t *bucket, cmph_uint32 size)
+{
+	assert(bucket);
+	if (bucket->capacity < size)
+	{
+		cmph_uint32 new_capacity = bucket->capacity + 1;
+		DEBUGP("Increasing current capacity %u to %u\n", bucket->capacity, size);
+		while (new_capacity < size)
+		{
+			new_capacity *= 2;
+		}
+		bucket->entries = (fch_bucket_entry_t *)realloc(bucket->entries, sizeof(fch_bucket_entry_t)*new_capacity);
+		assert(bucket->entries);
+		bucket->capacity = new_capacity;
+		DEBUGP("Increased\n");
+	}
+}
+
+static void fch_bucket_insert(fch_bucket_t *bucket, char *val, cmph_uint32 val_length)
+{
+	assert(bucket);
+	fch_bucket_reserve(bucket, bucket->size + 1);
+	(bucket->entries + bucket->size)->value = val;
+	(bucket->entries + bucket->size)->length = val_length;
+	++(bucket->size);
+}
+
+
+static cmph_uint8 fch_bucket_is_empty(fch_bucket_t *bucket)
+{
+	assert(bucket);
+	return (cmph_uint8)(bucket->size == 0);
+}
+
+static cmph_uint32 fch_bucket_size(fch_bucket_t *bucket)
+{
+	assert(bucket);
+	return bucket->size;
+}
+
+static char * fch_bucket_get_key(fch_bucket_t *bucket, cmph_uint32 index_key)
+{
+	assert(bucket); assert(index_key < bucket->size);
+	return (bucket->entries + index_key)->value;
+}
+
+static cmph_uint32 fch_bucket_get_length(fch_bucket_t *bucket, cmph_uint32 index_key)
+{
+	assert(bucket); assert(index_key < bucket->size);
+	return (bucket->entries + index_key)->length;
+}
+
+static void fch_bucket_print(fch_bucket_t * bucket, cmph_uint32 index)
+{
+	cmph_uint32 i;
+	assert(bucket);
+	fprintf(stderr, "Printing bucket %u ...\n", index);
+	for (i = 0; i < bucket->size; i++)
+	{
+		fprintf(stderr, "  key: %s\n", (bucket->entries + i)->value);
+	}
+}
+
+//////////////////////////////////////////////////////////////////////////////////////
+
+struct __fch_buckets_t
+{
+  fch_bucket_t * values;
+  cmph_uint32 nbuckets, max_size;
+  
+};
+
+fch_buckets_t * fch_buckets_new(cmph_uint32 nbuckets)
+{
+	cmph_uint32 i;
+	fch_buckets_t *buckets = (fch_buckets_t *)malloc(sizeof(fch_buckets_t));
+	assert(buckets);
+	buckets->values = (fch_bucket_t *)calloc((size_t)nbuckets, sizeof(fch_bucket_t));
+	for (i = 0; i < nbuckets; i++) fch_bucket_new(buckets->values + i); 
+	assert(buckets->values);
+	buckets->nbuckets = nbuckets;
+	buckets->max_size = 0;
+	return buckets;
+}
+
+cmph_uint8 fch_buckets_is_empty(fch_buckets_t * buckets, cmph_uint32 index)
+{
+	assert(index < buckets->nbuckets);
+	return fch_bucket_is_empty(buckets->values + index);
+}
+
+void fch_buckets_insert(fch_buckets_t * buckets, cmph_uint32 index, char * key, cmph_uint32 length)
+{
+	assert(index < buckets->nbuckets);
+	fch_bucket_insert(buckets->values + index, key, length);
+	if (fch_bucket_size(buckets->values + index) > buckets->max_size) 
+	{
+		buckets->max_size = fch_bucket_size(buckets->values + index);
+	}
+}
+
+cmph_uint32 fch_buckets_get_size(fch_buckets_t * buckets, cmph_uint32 index)
+{
+	assert(index < buckets->nbuckets);
+	return fch_bucket_size(buckets->values + index);
+}
+
+
+char * fch_buckets_get_key(fch_buckets_t * buckets, cmph_uint32 index, cmph_uint32 index_key)
+{
+	assert(index < buckets->nbuckets);
+	return fch_bucket_get_key(buckets->values + index, index_key);
+}
+
+cmph_uint32 fch_buckets_get_keylength(fch_buckets_t * buckets, cmph_uint32 index, cmph_uint32 index_key)
+{
+	assert(index < buckets->nbuckets);
+	return fch_bucket_get_length(buckets->values + index, index_key);
+}
+
+cmph_uint32 fch_buckets_get_max_size(fch_buckets_t * buckets)
+{
+	return buckets->max_size;
+}
+
+cmph_uint32 fch_buckets_get_nbuckets(fch_buckets_t * buckets)
+{
+	return buckets->nbuckets;
+}
+
+cmph_uint32 * fch_buckets_get_indexes_sorted_by_size(fch_buckets_t * buckets) 
+{
+	int i = 0;
+	cmph_uint32 sum = 0, value;
+	cmph_uint32 *nbuckets_size = (cmph_uint32 *) calloc((size_t)buckets->max_size + 1, sizeof(cmph_uint32));
+	cmph_uint32 * sorted_indexes = (cmph_uint32 *) calloc((size_t)buckets->nbuckets, sizeof(cmph_uint32));
+	
+	// collect how many buckets for each size.
+	for(i = 0; i < buckets->nbuckets; i++) nbuckets_size[fch_bucket_size(buckets->values + i)] ++;
+	
+	// calculating offset considering a decreasing order of buckets size.
+	value = nbuckets_size[buckets->max_size];
+	nbuckets_size[buckets->max_size] = sum;
+	for(i = (int)buckets->max_size - 1; i >= 0; i--)
+	{
+		sum += value;
+		value = nbuckets_size[i];
+		nbuckets_size[i] = sum;
+		
+	}
+	for(i = 0; i < buckets->nbuckets; i++) 
+	{
+		sorted_indexes[nbuckets_size[fch_bucket_size(buckets->values + i)]] = (cmph_uint32)i;
+		nbuckets_size[fch_bucket_size(buckets->values + i)] ++;
+	}	
+	free(nbuckets_size);
+	return sorted_indexes;
+}
+
+void fch_buckets_print(fch_buckets_t * buckets)
+{
+	cmph_uint32 i;
+	for (i = 0; i < buckets->nbuckets; i++) fch_bucket_print(buckets->values + i, i);
+}
+
+void fch_buckets_destroy(fch_buckets_t * buckets)
+{
+	cmph_uint32 i;
+	for (i = 0; i < buckets->nbuckets; i++) fch_bucket_destroy(buckets->values + i); 
+	free(buckets->values);
+	free(buckets);
+}
diff --git a/girepository/cmph/fch_buckets.h b/girepository/cmph/fch_buckets.h
new file mode 100644
index 0000000..2a1b8b2
--- /dev/null
+++ b/girepository/cmph/fch_buckets.h
@@ -0,0 +1,30 @@
+#ifndef __CMPH_FCH_BUCKETS_H__
+#define __CMPH_FCH_BUCKETS_H__
+
+#include "cmph_types.h"
+typedef struct __fch_buckets_t fch_buckets_t;
+
+fch_buckets_t * fch_buckets_new(cmph_uint32 nbuckets);
+
+cmph_uint8 fch_buckets_is_empty(fch_buckets_t * buckets, cmph_uint32 index);
+
+void fch_buckets_insert(fch_buckets_t * buckets, cmph_uint32 index, char * key, cmph_uint32 length);
+
+cmph_uint32 fch_buckets_get_size(fch_buckets_t * buckets, cmph_uint32 index);
+
+char * fch_buckets_get_key(fch_buckets_t * buckets, cmph_uint32 index, cmph_uint32 index_key);
+
+cmph_uint32 fch_buckets_get_keylength(fch_buckets_t * buckets, cmph_uint32 index, cmph_uint32 index_key);
+
+// returns the size of biggest bucket.
+cmph_uint32 fch_buckets_get_max_size(fch_buckets_t * buckets);
+
+// returns the number of buckets.
+cmph_uint32 fch_buckets_get_nbuckets(fch_buckets_t * buckets);
+
+cmph_uint32 * fch_buckets_get_indexes_sorted_by_size(fch_buckets_t * buckets);
+
+void fch_buckets_print(fch_buckets_t * buckets);
+
+void fch_buckets_destroy(fch_buckets_t * buckets);
+#endif
diff --git a/girepository/cmph/fch_structs.h b/girepository/cmph/fch_structs.h
new file mode 100755
index 0000000..fcd1555
--- /dev/null
+++ b/girepository/cmph/fch_structs.h
@@ -0,0 +1,30 @@
+#ifndef __CMPH_FCH_STRUCTS_H__
+#define __CMPH_FCH_STRUCTS_H__
+
+#include "hash_state.h"
+
+struct __fch_data_t
+{
+	cmph_uint32 m;       // words count
+	double c;      // constant c
+	cmph_uint32  b;      // parameter b = ceil(c*m/(log(m)/log(2) + 1)). Don't need to be stored 
+	double p1;     // constant p1 = ceil(0.6*m). Don't need to be stored 
+	double p2;     // constant p2 = ceil(0.3*b). Don't need to be stored 
+	cmph_uint32 *g;      // g function. 
+	hash_state_t *h1;    // h10 function. 
+	hash_state_t *h2;    // h20 function.
+};
+
+struct __fch_config_data_t
+{
+	CMPH_HASH hashfuncs[2];
+	cmph_uint32 m;       // words count
+	double c;      // constant c
+	cmph_uint32  b;      // parameter b = ceil(c*m/(log(m)/log(2) + 1)). Don't need to be stored 
+	double p1;     // constant p1 = ceil(0.6*m). Don't need to be stored 
+	double p2;     // constant p2 = ceil(0.3*b). Don't need to be stored 
+	cmph_uint32 *g;      // g function. 
+	hash_state_t *h1;    // h10 function. 
+	hash_state_t *h2;    // h20 function.
+};
+#endif
diff --git a/girepository/cmph/fnv_hash.c b/girepository/cmph/fnv_hash.c
new file mode 100644
index 0000000..aeaca8f
--- /dev/null
+++ b/girepository/cmph/fnv_hash.c
@@ -0,0 +1,53 @@
+#include "fnv_hash.h"
+#include <stdlib.h>
+
+fnv_state_t *fnv_state_new()
+{
+	fnv_state_t *state = (fnv_state_t *)malloc(sizeof(fnv_state_t));
+	state->hashfunc = CMPH_HASH_FNV;
+	return state;
+}
+
+void fnv_state_destroy(fnv_state_t *state)
+{
+	free(state);
+}
+
+cmph_uint32 fnv_hash(fnv_state_t *state, const char *k, cmph_uint32 keylen)
+{
+	const unsigned char *bp = (const unsigned char *)k;	
+	const unsigned char *be = bp + keylen;	
+	static unsigned int hval = 0;	
+
+	while (bp < be) 
+	{
+		
+		//hval *= 0x01000193; good for non-gcc compiler
+		hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24); //good for gcc
+
+		hval ^= *bp++;
+	}
+	return hval;
+}
+
+
+void fnv_state_dump(fnv_state_t *state, char **buf, cmph_uint32 *buflen)
+{
+	*buf = NULL;
+	*buflen = 0;
+	return;
+}
+
+fnv_state_t * fnv_state_copy(fnv_state_t *src_state)
+{
+	fnv_state_t *dest_state = (fnv_state_t *)malloc(sizeof(fnv_state_t));
+	dest_state->hashfunc = src_state->hashfunc;
+	return dest_state;
+}
+
+fnv_state_t *fnv_state_load(const char *buf, cmph_uint32 buflen)
+{
+	fnv_state_t *state = (fnv_state_t *)malloc(sizeof(fnv_state_t));
+	state->hashfunc = CMPH_HASH_FNV;
+	return state;
+}
diff --git a/girepository/cmph/fnv_hash.h b/girepository/cmph/fnv_hash.h
new file mode 100644
index 0000000..7f57946
--- /dev/null
+++ b/girepository/cmph/fnv_hash.h
@@ -0,0 +1,18 @@
+#ifndef __FNV_HASH_H__
+#define __FNV_HASH_H__
+
+#include "hash.h"
+
+typedef struct __fnv_state_t
+{
+	CMPH_HASH hashfunc;
+} fnv_state_t;
+
+fnv_state_t *fnv_state_new();
+cmph_uint32 fnv_hash(fnv_state_t *state, const char *k, cmph_uint32 keylen);
+void fnv_state_dump(fnv_state_t *state, char **buf, cmph_uint32 *buflen);
+fnv_state_t *fnv_state_copy(fnv_state_t *src_state);
+fnv_state_t *fnv_state_load(const char *buf, cmph_uint32 buflen);
+void fnv_state_destroy(fnv_state_t *state);
+
+#endif
diff --git a/girepository/cmph/graph.c b/girepository/cmph/graph.c
new file mode 100644
index 0000000..c29fd8b
--- /dev/null
+++ b/girepository/cmph/graph.c
@@ -0,0 +1,338 @@
+#include "graph.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <assert.h>
+#include <string.h>
+#include "vstack.h"
+#include "bitbool.h"
+
+//#define DEBUG
+#include "debug.h"
+
+/* static const cmph_uint8 bitmask[8] = { 1, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, 1 << 6, 1 << 7 }; */
+/* #define GETBIT(array, i) (array[(i) / 8] & bitmask[(i) % 8]) */
+/* #define SETBIT(array, i) (array[(i) / 8] |= bitmask[(i) % 8]) */
+/* #define UNSETBIT(array, i) (array[(i) / 8] &= (~(bitmask[(i) % 8]))) */
+
+#define abs_edge(e, i) (e % g->nedges + i * g->nedges)
+
+struct __graph_t
+{
+	cmph_uint32 nnodes;
+	cmph_uint32 nedges;
+	cmph_uint32 *edges;
+	cmph_uint32 *first;
+	cmph_uint32 *next;
+        cmph_uint8  *critical_nodes;   /* included -- Fabiano*/
+        cmph_uint32 ncritical_nodes;   /* included -- Fabiano*/
+	cmph_uint32 cedges;
+	int shrinking;
+};
+
+static cmph_uint32 EMPTY = UINT_MAX;
+
+graph_t *graph_new(cmph_uint32 nnodes, cmph_uint32 nedges)
+{
+	graph_t *graph = (graph_t *)malloc(sizeof(graph_t));
+	if (!graph) return NULL;
+
+	graph->edges = (cmph_uint32 *)malloc(sizeof(cmph_uint32) * 2 * nedges);
+	graph->next =  (cmph_uint32 *)malloc(sizeof(cmph_uint32) * 2 * nedges);
+	graph->first = (cmph_uint32 *)malloc(sizeof(cmph_uint32) * nnodes);
+        graph->critical_nodes = NULL; /* included -- Fabiano*/
+	graph->ncritical_nodes = 0;   /* included -- Fabiano*/
+	graph->nnodes = nnodes;
+	graph->nedges = nedges;
+
+	graph_clear_edges(graph);
+	return graph;
+}
+
+
+void graph_destroy(graph_t *graph)
+{
+	DEBUGP("Destroying graph\n");
+	free(graph->edges);
+	free(graph->first);
+	free(graph->next);
+        free(graph->critical_nodes); /* included -- Fabiano*/
+	free(graph);
+	return;
+}
+
+void graph_print(graph_t *g)
+{
+	cmph_uint32 i, e;
+	for (i = 0; i < g->nnodes; ++i)
+	{
+		DEBUGP("Printing edges connected to %u\n", i);
+		e = g->first[i];
+		if (e != EMPTY)
+		{
+			printf("%u -> %u\n", g->edges[abs_edge(e, 0)], g->edges[abs_edge(e, 1)]);
+			while ((e = g->next[e]) != EMPTY)
+			{
+				printf("%u -> %u\n", g->edges[abs_edge(e, 0)], g->edges[abs_edge(e, 1)]);
+			}
+		}
+			
+	}
+	return;
+}
+
+void graph_add_edge(graph_t *g, cmph_uint32 v1, cmph_uint32 v2)
+{
+	cmph_uint32 e = g->cedges;
+
+	assert(v1 < g->nnodes);
+	assert(v2 < g->nnodes);
+	assert(e < g->nedges);
+	assert(!g->shrinking);
+
+	g->next[e] = g->first[v1];
+	g->first[v1] = e;
+	g->edges[e] = v2;
+
+	g->next[e + g->nedges] = g->first[v2];
+	g->first[v2] = e + g->nedges;
+	g->edges[e + g->nedges] = v1;
+
+	++(g->cedges);
+}
+
+static int check_edge(graph_t *g, cmph_uint32 e, cmph_uint32 v1, cmph_uint32 v2)
+{
+	DEBUGP("Checking edge %u %u looking for %u %u\n", g->edges[abs_edge(e, 0)], g->edges[abs_edge(e, 1)], v1, v2);
+	if (g->edges[abs_edge(e, 0)] == v1 && g->edges[abs_edge(e, 1)] == v2) return 1;
+	if (g->edges[abs_edge(e, 0)] == v2 && g->edges[abs_edge(e, 1)] == v1) return 1;
+	return 0;
+}
+
+cmph_uint32 graph_edge_id(graph_t *g, cmph_uint32 v1, cmph_uint32 v2)
+{
+	cmph_uint32 e;
+	e = g->first[v1];
+	assert(e != EMPTY);
+	if (check_edge(g, e, v1, v2)) return abs_edge(e, 0);
+	do
+	{
+		e = g->next[e];
+		assert(e != EMPTY);
+	}
+	while (!check_edge(g, e, v1, v2));
+	return abs_edge(e, 0);
+}
+static void del_edge_point(graph_t *g, cmph_uint32 v1, cmph_uint32 v2)
+{
+	cmph_uint32 e, prev;
+
+	DEBUGP("Deleting edge point %u %u\n", v1, v2);
+	e = g->first[v1];
+	if (check_edge(g, e, v1, v2)) 
+	{
+		g->first[v1] = g->next[e];
+		//g->edges[e] = EMPTY;
+		DEBUGP("Deleted\n");
+		return;
+	}
+	DEBUGP("Checking linked list\n");
+	do
+	{
+		prev = e;
+		e = g->next[e];
+		assert(e != EMPTY);
+	}
+	while (!check_edge(g, e, v1, v2));
+
+	g->next[prev] = g->next[e];
+	//g->edges[e] = EMPTY;
+	DEBUGP("Deleted\n");
+}
+
+	
+void graph_del_edge(graph_t *g, cmph_uint32 v1, cmph_uint32 v2)
+{
+	g->shrinking = 1;
+	del_edge_point(g, v1, v2);
+	del_edge_point(g, v2, v1);
+}
+
+void graph_clear_edges(graph_t *g)
+{
+	cmph_uint32 i;
+	for (i = 0; i < g->nnodes; ++i) g->first[i] = EMPTY;
+	for (i = 0; i < g->nedges*2; ++i) 
+	{
+		g->edges[i] = EMPTY;
+		g->next[i] = EMPTY;
+	}
+	g->cedges = 0;
+	g->shrinking = 0;
+}
+
+static cmph_uint8 find_degree1_edge(graph_t *g, cmph_uint32 v, cmph_uint8 *deleted, cmph_uint32 *e)
+{
+	cmph_uint32 edge = g->first[v];
+	cmph_uint8 found = 0;
+	DEBUGP("Checking degree of vertex %u\n", v);
+	if (edge == EMPTY) return 0;
+	else if (!(GETBIT(deleted, abs_edge(edge, 0)))) 
+	{
+		found = 1;
+		*e = edge;
+	}
+	while(1)
+	{
+		edge = g->next[edge];
+		if (edge == EMPTY) break;
+		if (GETBIT(deleted, abs_edge(edge, 0))) continue;
+		if (found) return 0;
+		DEBUGP("Found first edge\n");
+		*e = edge;
+		found = 1;
+	}
+	return found;
+}
+
+static void cyclic_del_edge(graph_t *g, cmph_uint32 v, cmph_uint8 *deleted)
+{
+
+	cmph_uint32 e = 0;
+	cmph_uint8 degree1;
+	cmph_uint32 v1 = v;
+	cmph_uint32 v2 = 0;
+
+	degree1 = find_degree1_edge(g, v1, deleted, &e);
+	if (!degree1) return;
+	while(1) 
+	{
+		DEBUGP("Deleting edge %u (%u->%u)\n", e, g->edges[abs_edge(e, 0)], g->edges[abs_edge(e, 1)]);
+		SETBIT(deleted, abs_edge(e, 0));
+		
+		v2 = g->edges[abs_edge(e, 0)];
+		if (v2 == v1) v2 = g->edges[abs_edge(e, 1)];
+
+		DEBUGP("Checking if second endpoint %u has degree 1\n", v2); 
+		degree1 = find_degree1_edge(g, v2, deleted, &e);
+		if (degree1) 
+		{
+			DEBUGP("Inspecting vertex %u\n", v2);
+			v1 = v2;
+		}
+		else break;
+	}
+}
+
+int graph_is_cyclic(graph_t *g)
+{
+	cmph_uint32 i;
+	cmph_uint32 v;
+	cmph_uint8 *deleted = (cmph_uint8 *)malloc((g->nedges*sizeof(cmph_uint8))/8 + 1);
+	size_t deleted_len = g->nedges/8 + 1;
+	memset(deleted, 0, deleted_len);
+
+	DEBUGP("Looking for cycles in graph with %u vertices and %u edges\n", g->nnodes, g->nedges);
+	for (v = 0; v < g->nnodes; ++v)
+	{
+		cyclic_del_edge(g, v, deleted);
+	}
+	for (i = 0; i < g->nedges; ++i)
+	{
+		if (!(GETBIT(deleted, i))) 
+		{
+			DEBUGP("Edge %u %u->%u was not deleted\n", i, g->edges[i], g->edges[i + g->nedges]);
+			free(deleted);
+			return 1;
+		}
+	}
+	free(deleted);
+	return 0;
+}
+
+cmph_uint8 graph_node_is_critical(graph_t * g, cmph_uint32 v) /* included -- Fabiano */
+{
+        return (cmph_uint8)GETBIT(g->critical_nodes,v);
+}
+
+void graph_obtain_critical_nodes(graph_t *g) /* included -- Fabiano*/
+{
+        cmph_uint32 i;
+	cmph_uint32 v;
+	cmph_uint8 *deleted = (cmph_uint8 *)malloc((g->nedges*sizeof(cmph_uint8))/8+1);
+	size_t deleted_len = g->nedges/8 + 1;
+	memset(deleted, 0, deleted_len);
+	free(g->critical_nodes);
+	g->critical_nodes = (cmph_uint8 *)malloc((g->nnodes*sizeof(cmph_uint8))/8 + 1);
+	g->ncritical_nodes = 0;
+	memset(g->critical_nodes, 0, (g->nnodes*sizeof(cmph_uint8))/8 + 1);
+	DEBUGP("Looking for the 2-core in graph with %u vertices and %u edges\n", g->nnodes, g->nedges);
+	for (v = 0; v < g->nnodes; ++v)
+	{
+		cyclic_del_edge(g, v, deleted);
+	}
+
+	for (i = 0; i < g->nedges; ++i)
+	{
+		if (!(GETBIT(deleted,i))) 
+		{
+			DEBUGP("Edge %u %u->%u belongs to the 2-core\n", i, g->edges[i], g->edges[i + g->nedges]);
+			if(!(GETBIT(g->critical_nodes,g->edges[i]))) 
+			{
+			  g->ncritical_nodes ++;
+			  SETBIT(g->critical_nodes,g->edges[i]);
+			}
+			if(!(GETBIT(g->critical_nodes,g->edges[i + g->nedges]))) 
+			{
+			  g->ncritical_nodes ++;
+			  SETBIT(g->critical_nodes,g->edges[i + g->nedges]);
+			}
+		}
+	}
+	free(deleted);
+}
+
+cmph_uint8 graph_contains_edge(graph_t *g, cmph_uint32 v1, cmph_uint32 v2) /* included -- Fabiano*/
+{
+	cmph_uint32 e;
+	e = g->first[v1];
+	if(e == EMPTY) return 0;
+	if (check_edge(g, e, v1, v2)) return 1;
+	do
+	{
+		e = g->next[e];
+		if(e == EMPTY) return 0;
+	}
+	while (!check_edge(g, e, v1, v2));
+	return 1;
+}
+
+cmph_uint32 graph_vertex_id(graph_t *g, cmph_uint32 e, cmph_uint32 id) /* included -- Fabiano*/
+{
+  return (g->edges[e + id*g->nedges]);
+}
+
+cmph_uint32 graph_ncritical_nodes(graph_t *g) /* included -- Fabiano*/
+{
+  return g->ncritical_nodes;
+}
+
+graph_iterator_t graph_neighbors_it(graph_t *g, cmph_uint32 v)
+{
+	graph_iterator_t it;
+	it.vertex = v;
+	it.edge = g->first[v];
+	return it;
+}
+cmph_uint32 graph_next_neighbor(graph_t *g, graph_iterator_t* it)
+{
+	cmph_uint32 ret;
+	if(it->edge == EMPTY) return GRAPH_NO_NEIGHBOR; 
+	if (g->edges[it->edge] == it->vertex) ret = g->edges[it->edge + g->nedges];
+	else ret = g->edges[it->edge];
+	it->edge = g->next[it->edge];
+	return ret;
+}
+	
+
diff --git a/girepository/cmph/graph.h b/girepository/cmph/graph.h
new file mode 100644
index 0000000..e1b5de6
--- /dev/null
+++ b/girepository/cmph/graph.h
@@ -0,0 +1,40 @@
+#ifndef _CMPH_GRAPH_H__
+#define _CMPH_GRAPH_H__
+
+#include <limits.h>
+#include "cmph_types.h"
+
+#define GRAPH_NO_NEIGHBOR UINT_MAX
+
+typedef struct __graph_t graph_t;
+typedef struct __graph_iterator_t graph_iterator_t;
+struct __graph_iterator_t
+{
+	cmph_uint32 vertex;
+	cmph_uint32 edge;
+};
+
+
+
+graph_t *graph_new(cmph_uint32 nnodes, cmph_uint32 nedges);
+void graph_destroy(graph_t *graph);
+
+void graph_add_edge(graph_t *g, cmph_uint32 v1, cmph_uint32 v2);
+void graph_del_edge(graph_t *g, cmph_uint32 v1, cmph_uint32 v2);
+void graph_clear_edges(graph_t *g);
+cmph_uint32 graph_edge_id(graph_t *g, cmph_uint32 v1, cmph_uint32 v2);
+cmph_uint8 graph_contains_edge(graph_t *g, cmph_uint32 v1, cmph_uint32 v2);
+
+graph_iterator_t graph_neighbors_it(graph_t *g, cmph_uint32 v);
+cmph_uint32 graph_next_neighbor(graph_t *g, graph_iterator_t* it);
+
+void graph_obtain_critical_nodes(graph_t *g);            /* included -- Fabiano*/
+cmph_uint8 graph_node_is_critical(graph_t * g, cmph_uint32 v);     /* included -- Fabiano */
+cmph_uint32 graph_ncritical_nodes(graph_t *g);                /* included -- Fabiano*/
+cmph_uint32 graph_vertex_id(graph_t *g, cmph_uint32 e, cmph_uint32 id); /* included -- Fabiano*/
+
+int graph_is_cyclic(graph_t *g);
+
+void graph_print(graph_t *);
+
+#endif
diff --git a/girepository/cmph/hash.c b/girepository/cmph/hash.c
new file mode 100644
index 0000000..be86d6e
--- /dev/null
+++ b/girepository/cmph/hash.c
@@ -0,0 +1,216 @@
+#include "hash_state.h"
+#include <stdlib.h>
+#include <assert.h>
+#include <limits.h>
+#include <string.h>
+
+//#define DEBUG
+#include "debug.h"
+
+const char *cmph_hash_names[] = { "jenkins", NULL };
+
+hash_state_t *hash_state_new(CMPH_HASH hashfunc, cmph_uint32 hashsize)
+{
+	hash_state_t *state = NULL;
+	switch (hashfunc)
+	{
+		case CMPH_HASH_JENKINS:
+	  		DEBUGP("Jenkins function - %u\n", hashsize);
+			state = (hash_state_t *)jenkins_state_new(hashsize);
+	  		DEBUGP("Jenkins function created\n");
+			break;
+		default:
+			assert(0);
+	}
+	state->hashfunc = hashfunc;
+	return state;
+}
+cmph_uint32 hash(hash_state_t *state, const char *key, cmph_uint32 keylen)
+{
+	switch (state->hashfunc)
+	{
+		case CMPH_HASH_JENKINS:
+			return jenkins_hash((jenkins_state_t *)state, key, keylen);
+		default:
+			assert(0);
+	}
+	assert(0);
+	return 0;
+}
+
+void hash_vector(hash_state_t *state, const char *key, cmph_uint32 keylen, cmph_uint32 * hashes)
+{
+	switch (state->hashfunc)
+	{
+		case CMPH_HASH_JENKINS:
+			jenkins_hash_vector_((jenkins_state_t *)state, key, keylen, hashes);
+			break;
+		default:
+			assert(0);
+	}
+}
+
+
+void hash_state_dump(hash_state_t *state, char **buf, cmph_uint32 *buflen)
+{
+	char *algobuf;
+	size_t len;
+	switch (state->hashfunc)
+	{
+		case CMPH_HASH_JENKINS:
+			jenkins_state_dump((jenkins_state_t *)state, &algobuf, buflen);
+			if (*buflen == UINT_MAX) return;
+			break;
+		default:
+			assert(0);
+	}
+	*buf = (char *)malloc(strlen(cmph_hash_names[state->hashfunc]) + 1 + *buflen);
+	memcpy(*buf, cmph_hash_names[state->hashfunc], strlen(cmph_hash_names[state->hashfunc]) + 1);
+	DEBUGP("Algobuf is %u\n", *(cmph_uint32 *)algobuf);
+	len = *buflen;
+	memcpy(*buf + strlen(cmph_hash_names[state->hashfunc]) + 1, algobuf, len);
+	*buflen  = (cmph_uint32)strlen(cmph_hash_names[state->hashfunc]) + 1 + *buflen;
+	free(algobuf);
+	return;
+}
+
+hash_state_t * hash_state_copy(hash_state_t *src_state)
+{
+	hash_state_t *dest_state = NULL;
+	switch (src_state->hashfunc)
+	{
+		case CMPH_HASH_JENKINS:
+			dest_state = (hash_state_t *)jenkins_state_copy((jenkins_state_t *)src_state);
+			break;
+		default:
+			assert(0);
+	}
+	dest_state->hashfunc = src_state->hashfunc;
+	return dest_state;
+}
+
+hash_state_t *hash_state_load(const char *buf, cmph_uint32 buflen)
+{
+	cmph_uint32 i;
+	cmph_uint32 offset;
+	CMPH_HASH hashfunc = CMPH_HASH_COUNT;
+	for (i = 0; i < CMPH_HASH_COUNT; ++i)
+	{
+		if (strcmp(buf, cmph_hash_names[i]) == 0)
+		{
+			hashfunc = i;
+			break;
+		}
+	}
+	if (hashfunc == CMPH_HASH_COUNT) return NULL;
+	offset = (cmph_uint32)strlen(cmph_hash_names[hashfunc]) + 1;
+	switch (hashfunc)
+	{
+		case CMPH_HASH_JENKINS:
+			return (hash_state_t *)jenkins_state_load(buf + offset, buflen - offset);
+		default:
+			return NULL;
+	}
+	return NULL;
+}
+void hash_state_destroy(hash_state_t *state)
+{
+	switch (state->hashfunc)
+	{
+		case CMPH_HASH_JENKINS:
+			jenkins_state_destroy((jenkins_state_t *)state);
+			break;
+		default:
+			assert(0);
+	}
+	return;
+}
+
+/** \fn void hash_state_pack(hash_state_t *state, void *hash_packed)
+ *  \brief Support the ability to pack a hash function into a preallocated contiguous memory space pointed by hash_packed.
+ *  \param state points to the hash function
+ *  \param hash_packed pointer to the contiguous memory area used to store the hash function. The size of hash_packed must be at least hash_state_packed_size()
+ *  
+ * Support the ability to pack a hash function into a preallocated contiguous memory space pointed by hash_packed.
+ * However, the hash function type must be packed outside.
+ */
+void hash_state_pack(hash_state_t *state, void *hash_packed)
+{
+	switch (state->hashfunc)
+	{
+		case CMPH_HASH_JENKINS:
+			// pack the jenkins hash function			
+			jenkins_state_pack((jenkins_state_t *)state, hash_packed);
+			break;
+		default:
+			assert(0);
+	}
+	return;	
+}
+
+/** \fn cmph_uint32 hash_state_packed_size(CMPH_HASH hashfunc)
+ *  \brief Return the amount of space needed to pack a hash function.
+ *  \param hashfunc function type
+ *  \return the size of the packed function or zero for failures
+ */ 
+cmph_uint32 hash_state_packed_size(CMPH_HASH hashfunc)
+{
+	cmph_uint32 size = 0;
+	switch (hashfunc)
+	{
+		case CMPH_HASH_JENKINS:
+			size += jenkins_state_packed_size();
+			break;
+		default:
+			assert(0);
+	}
+	return size;
+}
+
+/** \fn cmph_uint32 hash_packed(void *hash_packed, CMPH_HASH hashfunc, const char *k, cmph_uint32 keylen)
+ *  \param hash_packed is a pointer to a contiguous memory area
+ *  \param hashfunc is the type of the hash function packed in hash_packed
+ *  \param key is a pointer to a key
+ *  \param keylen is the key length
+ *  \return an integer that represents a hash value of 32 bits.
+ */
+cmph_uint32 hash_packed(void *hash_packed, CMPH_HASH hashfunc, const char *k, cmph_uint32 keylen)
+{
+	switch (hashfunc)
+	{
+		case CMPH_HASH_JENKINS:
+			return jenkins_hash_packed(hash_packed, k, keylen);
+		default:
+			assert(0);
+	}
+	assert(0);
+	return 0;
+}
+
+/** \fn hash_vector_packed(void *hash_packed, CMPH_HASH hashfunc, const char *k, cmph_uint32 keylen, cmph_uint32 * hashes)
+ *  \param hash_packed is a pointer to a contiguous memory area
+ *  \param key is a pointer to a key
+ *  \param keylen is the key length
+ *  \param hashes is a pointer to a memory large enough to fit three 32-bit integers.
+ */
+void hash_vector_packed(void *hash_packed, CMPH_HASH hashfunc, const char *k, cmph_uint32 keylen, cmph_uint32 * hashes)
+{		
+	switch (hashfunc)
+	{
+		case CMPH_HASH_JENKINS:
+			jenkins_hash_vector_packed(hash_packed, k, keylen, hashes);
+			break;
+		default:
+			assert(0);
+	}
+}
+
+
+/** \fn CMPH_HASH hash_get_type(hash_state_t *state);
+ *  \param state is a pointer to a hash_state_t structure
+ *  \return the hash function type pointed by state
+ */
+CMPH_HASH hash_get_type(hash_state_t *state)
+{
+	return state->hashfunc;
+}
diff --git a/girepository/cmph/hash.h b/girepository/cmph/hash.h
new file mode 100644
index 0000000..0ec4ce1
--- /dev/null
+++ b/girepository/cmph/hash.h
@@ -0,0 +1,76 @@
+#ifndef __CMPH_HASH_H__
+#define __CMPH_HASH_H__
+
+#include "cmph_types.h"
+
+typedef union __hash_state_t hash_state_t;
+
+hash_state_t *hash_state_new(CMPH_HASH, cmph_uint32 hashsize);
+
+/** \fn cmph_uint32 hash(hash_state_t *state, const char *key, cmph_uint32 keylen);
+ *  \param state is a pointer to a hash_state_t structure
+ *  \param key is a pointer to a key
+ *  \param keylen is the key length
+ *  \return an integer that represents a hash value of 32 bits.
+ */
+cmph_uint32 hash(hash_state_t *state, const char *key, cmph_uint32 keylen);
+
+/** \fn void hash_vector(hash_state_t *state, const char *key, cmph_uint32 keylen, cmph_uint32 * hashes);
+ *  \param state is a pointer to a hash_state_t structure
+ *  \param key is a pointer to a key
+ *  \param keylen is the key length
+ *  \param hashes is a pointer to a memory large enough to fit three 32-bit integers.
+ */
+void hash_vector(hash_state_t *state, const char *key, cmph_uint32 keylen, cmph_uint32 * hashes);
+
+void hash_state_dump(hash_state_t *state, char **buf, cmph_uint32 *buflen);
+
+hash_state_t * hash_state_copy(hash_state_t *src_state);
+
+hash_state_t *hash_state_load(const char *buf, cmph_uint32 buflen);
+
+void hash_state_destroy(hash_state_t *state);
+
+/** \fn void hash_state_pack(hash_state_t *state, void *hash_packed);
+ *  \brief Support the ability to pack a hash function into a preallocated contiguous memory space pointed by hash_packed.
+ *  \param state points to the hash function
+ *  \param hash_packed pointer to the contiguous memory area used to store the hash function. The size of hash_packed must be at least hash_state_packed_size()
+ *  
+ * Support the ability to pack a hash function into a preallocated contiguous memory space pointed by hash_packed.
+ * However, the hash function type must be packed outside.
+ */
+void hash_state_pack(hash_state_t *state, void *hash_packed);
+
+/** \fn cmph_uint32 hash_packed(void *hash_packed, CMPH_HASH hashfunc, const char *k, cmph_uint32 keylen);
+ *  \param hash_packed is a pointer to a contiguous memory area
+ *  \param hashfunc is the type of the hash function packed in hash_packed
+ *  \param key is a pointer to a key
+ *  \param keylen is the key length
+ *  \return an integer that represents a hash value of 32 bits.
+ */
+cmph_uint32 hash_packed(void *hash_packed, CMPH_HASH hashfunc, const char *k, cmph_uint32 keylen);
+
+/** \fn cmph_uint32 hash_state_packed_size(CMPH_HASH hashfunc)
+ *  \brief Return the amount of space needed to pack a hash function.
+ *  \param hashfunc function type
+ *  \return the size of the packed function or zero for failures
+ */ 
+cmph_uint32 hash_state_packed_size(CMPH_HASH hashfunc);
+
+
+/** \fn hash_vector_packed(void *hash_packed, CMPH_HASH hashfunc, const char *k, cmph_uint32 keylen, cmph_uint32 * hashes);
+ *  \param hash_packed is a pointer to a contiguous memory area
+ *  \param key is a pointer to a key
+ *  \param keylen is the key length
+ *  \param hashes is a pointer to a memory large enough to fit three 32-bit integers.
+ */
+void hash_vector_packed(void *hash_packed, CMPH_HASH hashfunc, const char *k, cmph_uint32 keylen, cmph_uint32 * hashes);
+
+
+/** \fn CMPH_HASH hash_get_type(hash_state_t *state);
+ *  \param state is a pointer to a hash_state_t structure
+ *  \return the hash function type pointed by state
+ */
+CMPH_HASH hash_get_type(hash_state_t *state);
+
+#endif
diff --git a/girepository/cmph/hash_state.h b/girepository/cmph/hash_state.h
new file mode 100644
index 0000000..1b567dc
--- /dev/null
+++ b/girepository/cmph/hash_state.h
@@ -0,0 +1,12 @@
+#ifndef __HASH_STATE_H__
+#define __HASH_STATE_H__
+
+#include "hash.h"
+#include "jenkins_hash.h"
+union __hash_state_t
+{
+	CMPH_HASH hashfunc;
+	jenkins_state_t jenkins;
+};
+
+#endif
diff --git a/girepository/cmph/hashtree.c b/girepository/cmph/hashtree.c
new file mode 100644
index 0000000..2f3567e
--- /dev/null
+++ b/girepository/cmph/hashtree.c
@@ -0,0 +1,289 @@
+#include "graph.h"
+#include "hashtree.h"
+#include "cmph_structs.h"
+#include "hastree_structs.h"
+#include "hash.h"
+#include "bitbool.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+
+//#define DEBUG
+#include "debug.h"
+
+hashtree_config_data_t *hashtree_config_new()
+{
+	hashtree_config_data_t *hashtree;
+	hashtree = (hashtree_config_data_t *)malloc(sizeof(hashtree_config_data_t));
+	if (!hashtree) return NULL;
+	memset(hashtree, 0, sizeof(hashtree_config_data_t));
+	hashtree->hashfuncs[0] = CMPH_HASH_JENKINS;
+	hashtree->hashfuncs[1] = CMPH_HASH_JENKINS;
+	hashtree->hashfuncs[2] = CMPH_HASH_JENKINS;
+	hashtree->memory = 32 * 1024 * 1024;
+	return hashtree;
+}
+void hashtree_config_destroy(cmph_config_t *mph)
+{
+	hashtree_config_data_t *data = (hashtree_config_data_t *)mph->data;
+	DEBUGP("Destroying algorithm dependent data\n");
+	free(data);
+}
+
+void hashtree_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs)
+{
+	hashtree_config_data_t *hashtree = (hashtree_config_data_t *)mph->data;
+	CMPH_HASH *hashptr = hashfuncs;
+	cmph_uint32 i = 0;
+	while(*hashptr != CMPH_HASH_COUNT)
+	{
+		if (i >= 3) break; //hashtree only uses three hash functions
+		hashtree->hashfuncs[i] = *hashptr;	
+		++i, ++hashptr;
+	}
+}
+
+cmph_t *hashtree_new(cmph_config_t *mph, double c)
+{
+	cmph_t *mphf = NULL;
+	hashtree_data_t *hashtreef = NULL;
+
+	cmph_uint32 i;
+	cmph_uint32 iterations = 20;
+	cmph_uint8 *visited = NULL;
+	hashtree_config_data_t *hashtree = (hashtree_config_data_t *)mph->data;
+	hashtree->m = mph->key_source->nkeys;	
+	hashtree->n = ceil(c * mph->key_source->nkeys);	
+	DEBUGP("m (edges): %u n (vertices): %u c: %f\n", hashtree->m, hashtree->n, c);
+	hashtree->graph = graph_new(hashtree->n, hashtree->m);
+	DEBUGP("Created graph\n");
+
+	hashtree->hashes = (hash_state_t **)malloc(sizeof(hash_state_t *)*3);
+	for(i = 0; i < 3; ++i) hashtree->hashes[i] = NULL;
+	//Mapping step
+	if (mph->verbosity)
+	{
+		fprintf(stderr, "Entering mapping step for mph creation of %u keys with graph sized %u\n", hashtree->m, hashtree->n);
+	}
+	while(1)
+	{
+		int ok;
+		hashtree->hashes[0] = hash_state_new(hashtree->hashfuncs[0], hashtree->n);
+		hashtree->hashes[1] = hash_state_new(hashtree->hashfuncs[1], hashtree->n);
+		ok = hashtree_gen_edges(mph);
+		if (!ok)
+		{
+			--iterations;
+			hash_state_destroy(hashtree->hashes[0]);
+			hashtree->hashes[0] = NULL;
+			hash_state_destroy(hashtree->hashes[1]);
+			hashtree->hashes[1] = NULL;
+			DEBUGP("%u iterations remaining\n", iterations);
+			if (mph->verbosity)
+			{
+				fprintf(stderr, "Acyclic graph creation failure - %u iterations remaining\n", iterations);
+			}
+			if (iterations == 0) break;
+		} 
+		else break;	
+	}
+	if (iterations == 0)
+	{
+		graph_destroy(hashtree->graph);	
+		return NULL;
+	}
+
+	//Assignment step
+	if (mph->verbosity)
+	{
+		fprintf(stderr, "Starting assignment step\n");
+	}
+	DEBUGP("Assignment step\n");
+ 	visited = (char *)malloc(hashtree->n/8 + 1);
+	memset(visited, 0, hashtree->n/8 + 1);
+	free(hashtree->g);
+	hashtree->g = (cmph_uint32 *)malloc(hashtree->n * sizeof(cmph_uint32));
+	assert(hashtree->g);
+	for (i = 0; i < hashtree->n; ++i)
+	{
+	        if (!GETBIT(visited,i))
+		{
+			hashtree->g[i] = 0;
+			hashtree_traverse(hashtree, visited, i);
+		}
+	}
+	graph_destroy(hashtree->graph);	
+	free(visited);
+	hashtree->graph = NULL;
+
+	mphf = (cmph_t *)malloc(sizeof(cmph_t));
+	mphf->algo = mph->algo;
+	hashtreef = (hashtree_data_t *)malloc(sizeof(hashtree_data_t));
+	hashtreef->g = hashtree->g;
+	hashtree->g = NULL; //transfer memory ownership
+	hashtreef->hashes = hashtree->hashes;
+	hashtree->hashes = NULL; //transfer memory ownership
+	hashtreef->n = hashtree->n;
+	hashtreef->m = hashtree->m;
+	mphf->data = hashtreef;
+	mphf->size = hashtree->m;
+	DEBUGP("Successfully generated minimal perfect hash\n");
+	if (mph->verbosity)
+	{
+		fprintf(stderr, "Successfully generated minimal perfect hash function\n");
+	}
+	return mphf;
+}
+
+static void hashtree_traverse(hashtree_config_data_t *hashtree, cmph_uint8 *visited, cmph_uint32 v)
+{
+
+	graph_iterator_t it = graph_neighbors_it(hashtree->graph, v);
+	cmph_uint32 neighbor = 0;
+	SETBIT(visited,v);
+	
+	DEBUGP("Visiting vertex %u\n", v);
+	while((neighbor = graph_next_neighbor(hashtree->graph, &it)) != GRAPH_NO_NEIGHBOR)
+	{
+		DEBUGP("Visiting neighbor %u\n", neighbor);
+		if(GETBIT(visited,neighbor)) continue;
+		DEBUGP("Visiting neighbor %u\n", neighbor);
+		DEBUGP("Visiting edge %u->%u with id %u\n", v, neighbor, graph_edge_id(hashtree->graph, v, neighbor));
+		hashtree->g[neighbor] = graph_edge_id(hashtree->graph, v, neighbor) - hashtree->g[v];
+		DEBUGP("g is %u (%u - %u mod %u)\n", hashtree->g[neighbor], graph_edge_id(hashtree->graph, v, neighbor), hashtree->g[v], hashtree->m);
+		hashtree_traverse(hashtree, visited, neighbor);
+	}
+}
+		
+static int hashtree_gen_edges(cmph_config_t *mph)
+{
+	cmph_uint32 e;
+	hashtree_config_data_t *hashtree = (hashtree_config_data_t *)mph->data;
+	int cycles = 0;
+
+	DEBUGP("Generating edges for %u vertices with hash functions %s and %s\n", hashtree->n, cmph_hash_names[hashtree->hashfuncs[0]], cmph_hash_names[hashtree->hashfuncs[1]]);
+	graph_clear_edges(hashtree->graph);	
+	mph->key_source->rewind(mph->key_source->data);
+	for (e = 0; e < mph->key_source->nkeys; ++e)
+	{
+		cmph_uint32 h1, h2;
+		cmph_uint32 keylen;
+		char *key;
+		mph->key_source->read(mph->key_source->data, &key, &keylen);
+		h1 = hash(hashtree->hashes[0], key, keylen) % hashtree->n;
+		h2 = hash(hashtree->hashes[1], key, keylen) % hashtree->n;
+		if (h1 == h2) if (++h2 >= hashtree->n) h2 = 0;
+		if (h1 == h2) 
+		{
+			if (mph->verbosity) fprintf(stderr, "Self loop for key %u\n", e);
+			mph->key_source->dispose(mph->key_source->data, key, keylen);
+			return 0;
+		}
+		DEBUGP("Adding edge: %u -> %u for key %s\n", h1, h2, key);
+		mph->key_source->dispose(mph->key_source->data, key, keylen);
+		graph_add_edge(hashtree->graph, h1, h2);
+	}
+	cycles = graph_is_cyclic(hashtree->graph);
+	if (mph->verbosity && cycles) fprintf(stderr, "Cyclic graph generated\n");
+	DEBUGP("Looking for cycles: %u\n", cycles);
+
+	return ! cycles;
+}
+
+int hashtree_dump(cmph_t *mphf, FILE *fd)
+{
+	char *buf = NULL;
+	cmph_uint32 buflen;
+	cmph_uint32 two = 2; //number of hash functions
+	hashtree_data_t *data = (hashtree_data_t *)mphf->data;
+	__cmph_dump(mphf, fd);
+
+	fwrite(&two, sizeof(cmph_uint32), 1, fd);
+	hash_state_dump(data->hashes[0], &buf, &buflen);
+	DEBUGP("Dumping hash state with %u bytes to disk\n", buflen);
+	fwrite(&buflen, sizeof(cmph_uint32), 1, fd);
+	fwrite(buf, buflen, 1, fd);
+	free(buf);
+
+	hash_state_dump(data->hashes[1], &buf, &buflen);
+	DEBUGP("Dumping hash state with %u bytes to disk\n", buflen);
+	fwrite(&buflen, sizeof(cmph_uint32), 1, fd);
+	fwrite(buf, buflen, 1, fd);
+	free(buf);
+
+	fwrite(&(data->n), sizeof(cmph_uint32), 1, fd);
+	fwrite(&(data->m), sizeof(cmph_uint32), 1, fd);
+	
+	fwrite(data->g, sizeof(cmph_uint32)*data->n, 1, fd);
+	#ifdef DEBUG
+	fprintf(stderr, "G: ");
+	for (i = 0; i < data->n; ++i) fprintf(stderr, "%u ", data->g[i]);
+	fprintf(stderr, "\n");
+	#endif
+	return 1;
+}
+
+void hashtree_load(FILE *f, cmph_t *mphf)
+{
+	cmph_uint32 nhashes;
+	char *buf = NULL;
+	cmph_uint32 buflen;
+	cmph_uint32 i;
+	hashtree_data_t *hashtree = (hashtree_data_t *)malloc(sizeof(hashtree_data_t));
+
+	DEBUGP("Loading hashtree mphf\n");
+	mphf->data = hashtree;
+	fread(&nhashes, sizeof(cmph_uint32), 1, f);
+	hashtree->hashes = (hash_state_t **)malloc(sizeof(hash_state_t *)*(nhashes + 1));
+	hashtree->hashes[nhashes] = NULL;
+	DEBUGP("Reading %u hashes\n", nhashes);
+	for (i = 0; i < nhashes; ++i)
+	{
+		hash_state_t *state = NULL;
+		fread(&buflen, sizeof(cmph_uint32), 1, f);
+		DEBUGP("Hash state has %u bytes\n", buflen);
+		buf = (char *)malloc(buflen);
+		fread(buf, buflen, 1, f);
+		state = hash_state_load(buf, buflen);
+		hashtree->hashes[i] = state;
+		free(buf);
+	}
+
+	DEBUGP("Reading m and n\n");
+	fread(&(hashtree->n), sizeof(cmph_uint32), 1, f);	
+	fread(&(hashtree->m), sizeof(cmph_uint32), 1, f);	
+
+	hashtree->g = (cmph_uint32 *)malloc(sizeof(cmph_uint32)*hashtree->n);
+	fread(hashtree->g, hashtree->n*sizeof(cmph_uint32), 1, f);
+	#ifdef DEBUG
+	fprintf(stderr, "G: ");
+	for (i = 0; i < hashtree->n; ++i) fprintf(stderr, "%u ", hashtree->g[i]);
+	fprintf(stderr, "\n");
+	#endif
+	return;
+}
+		
+
+cmph_uint32 hashtree_search(cmph_t *mphf, const char *key, cmph_uint32 keylen)
+{
+	hashtree_data_t *hashtree = mphf->data;
+	cmph_uint32 h1 = hash(hashtree->hashes[0], key, keylen) % hashtree->n;
+	cmph_uint32 h2 = hash(hashtree->hashes[1], key, keylen) % hashtree->n;
+	DEBUGP("key: %s h1: %u h2: %u\n", key, h1, h2);
+	if (h1 == h2 && ++h2 >= hashtree->n) h2 = 0;
+	DEBUGP("key: %s g[h1]: %u g[h2]: %u edges: %u\n", key, hashtree->g[h1], hashtree->g[h2], hashtree->m);
+	return (hashtree->g[h1] + hashtree->g[h2]) % hashtree->m;
+}
+void hashtree_destroy(cmph_t *mphf)
+{
+	hashtree_data_t *data = (hashtree_data_t *)mphf->data;
+	free(data->g);	
+	hash_state_destroy(data->hashes[0]);
+	hash_state_destroy(data->hashes[1]);
+	free(data->hashes);
+	free(data);
+	free(mphf);
+}
diff --git a/girepository/cmph/hashtree.h b/girepository/cmph/hashtree.h
new file mode 100644
index 0000000..8bff674
--- /dev/null
+++ b/girepository/cmph/hashtree.h
@@ -0,0 +1,19 @@
+#ifndef __CMPH_HASHTREE_H__
+#define __CMPH_HASHTREE_H__
+
+#include "cmph.h"
+
+typedef struct __hashtree_data_t hashtree_data_t;
+typedef struct __hashtree_config_data_t hashtree_config_data_t;
+
+hashtree_config_data_t *hashtree_config_new();
+void hashtree_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs);
+void hashtree_config_set_leaf_algo(cmph_config_t *mph, CMPH_ALGO leaf_algo);
+void hashtree_config_destroy(cmph_config_t *mph);
+cmph_t *hashtree_new(cmph_config_t *mph, double c);
+
+void hashtree_load(FILE *f, cmph_t *mphf);
+int hashtree_dump(cmph_t *mphf, FILE *f);
+void hashtree_destroy(cmph_t *mphf);
+cmph_uint32 hashtree_search(cmph_t *mphf, const char *key, cmph_uint32 keylen);
+#endif
diff --git a/girepository/cmph/hashtree_structs.h b/girepository/cmph/hashtree_structs.h
new file mode 100644
index 0000000..7258cd3
--- /dev/null
+++ b/girepository/cmph/hashtree_structs.h
@@ -0,0 +1,32 @@
+#ifndef __CMPH_HASHTREE_STRUCTS_H__
+#define __CMPH_HASHTREE_STRUCTS_H__
+
+#include "hash_state.h"
+
+struct __hashtree_data_t
+{
+	cmph_uint32 m; //edges (words) count
+	double c; //constant c
+	cmph_uint8 *size; //size[i] stores the number of edges represented by g[i]
+	cmph_uint32 **g;
+	cmph_uint32 k; //number of components
+	hash_state_t **h1; 
+	hash_state_t **h2;
+	hash_state_t *h3;
+};
+
+struct __hashtree_config_data_t
+{
+	CMPH_ALGO leaf_algo;
+	CMPH_HASH hashfuncs[3];
+	cmph_uint32 m; //edges (words) count
+	cmph_uint8 *size; //size[i] stores the number of edges represented by g[i]
+	cmph_uint32 *offset; //offset[i] stores the sum size[0] + ... size[i - 1]
+	cmph_uint32 k; //number of components
+	cmph_uint32 memory;
+	hash_state_t **h1; 
+	hash_state_t **h2;
+	hash_state_t *h3;
+};
+
+#endif
diff --git a/girepository/cmph/jenkins_hash.c b/girepository/cmph/jenkins_hash.c
new file mode 100644
index 0000000..f5233a5
--- /dev/null
+++ b/girepository/cmph/jenkins_hash.c
@@ -0,0 +1,297 @@
+#include "jenkins_hash.h"
+#include <stdlib.h>
+#ifdef WIN32
+#define _USE_MATH_DEFINES //For M_LOG2E
+#endif
+#include <math.h>
+#include <limits.h>
+#include <string.h>
+
+//#define DEBUG
+#include "debug.h"
+
+#define hashsize(n) ((cmph_uint32)1<<(n))
+#define hashmask(n) (hashsize(n)-1)
+
+
+
+//#define NM2 /* Define this if you do not want power of 2 table sizes*/
+
+
+/*
+   --------------------------------------------------------------------
+   mix -- mix 3 32-bit values reversibly.
+   For every delta with one or two bits set, and the deltas of all three
+   high bits or all three low bits, whether the original value of a,b,c
+   is almost all zero or is uniformly distributed,
+ * If mix() is run forward or backward, at least 32 bits in a,b,c
+ have at least 1/4 probability of changing.
+ * If mix() is run forward, every bit of c will change between 1/3 and
+ 2/3 of the time.  (Well, 22/100 and 78/100 for some 2-bit deltas.)
+ mix() was built out of 36 single-cycle latency instructions in a 
+ structure that could supported 2x parallelism, like so:
+ a -= b; 
+ a -= c; x = (c>>13);
+ b -= c; a ^= x;
+ b -= a; x = (a<<8);
+ c -= a; b ^= x;
+ c -= b; x = (b>>13);
+ ...
+ Unfortunately, superscalar Pentiums and Sparcs can't take advantage 
+ of that parallelism.  They've also turned some of those single-cycle
+ latency instructions into multi-cycle latency instructions.  Still,
+ this is the fastest good hash I could find.  There were about 2^^68
+ to choose from.  I only looked at a billion or so.
+ --------------------------------------------------------------------
+ */
+#define mix(a,b,c) \
+{ \
+	a -= b; a -= c; a ^= (c>>13); \
+	b -= c; b -= a; b ^= (a<<8); \
+	c -= a; c -= b; c ^= (b>>13); \
+	a -= b; a -= c; a ^= (c>>12);  \
+	b -= c; b -= a; b ^= (a<<16); \
+	c -= a; c -= b; c ^= (b>>5); \
+	a -= b; a -= c; a ^= (c>>3);  \
+	b -= c; b -= a; b ^= (a<<10); \
+	c -= a; c -= b; c ^= (b>>15); \
+}
+
+/*
+   --------------------------------------------------------------------
+   hash() -- hash a variable-length key into a 32-bit value
+k       : the key (the unaligned variable-length array of bytes)
+len     : the length of the key, counting by bytes
+initval : can be any 4-byte value
+Returns a 32-bit value.  Every bit of the key affects every bit of
+the return value.  Every 1-bit and 2-bit delta achieves avalanche.
+About 6*len+35 instructions.
+
+The best hash table sizes are powers of 2.  There is no need to do
+mod a prime (mod is sooo slow!).  If you need less than 32 bits,
+use a bitmask.  For example, if you need only 10 bits, do
+h = (h & hashmask(10));
+In which case, the hash table should have hashsize(10) elements.
+
+If you are hashing n strings (cmph_uint8 **)k, do it like this:
+for (i=0, h=0; i<n; ++i) h = hash( k[i], len[i], h);
+
+By Bob Jenkins, 1996.  bob_jenkins burtleburtle net   You may use this
+code any way you wish, private, educational, or commercial.  It's free.
+
+See http://burtleburtle.net/bob/hash/evahash.html
+Use for hash table lookup, or anything where one collision in 2^^32 is
+acceptable.  Do NOT use for cryptographic purposes.
+--------------------------------------------------------------------
+ */
+jenkins_state_t *jenkins_state_new(cmph_uint32 size) //size of hash table
+{
+	jenkins_state_t *state = (jenkins_state_t *)malloc(sizeof(jenkins_state_t));
+	DEBUGP("Initializing jenkins hash\n");
+	state->seed = ((cmph_uint32)rand() % size);
+	return state;
+}
+void jenkins_state_destroy(jenkins_state_t *state)
+{
+	free(state);
+}
+
+
+inline void __jenkins_hash_vector(cmph_uint32 seed, const char *k, cmph_uint32 keylen, cmph_uint32 * hashes)
+{
+	register cmph_uint32 len, length;
+
+	/* Set up the internal state */
+	length = keylen;
+	len = length;
+	hashes[0] = hashes[1] = 0x9e3779b9;  /* the golden ratio; an arbitrary value */
+	hashes[2] = seed;   /* the previous hash value - seed in our case */
+
+	/*---------------------------------------- handle most of the key */
+	while (len >= 12)
+	{
+		hashes[0] += ((cmph_uint32)k[0] +((cmph_uint32)k[1]<<8) +((cmph_uint32)k[2]<<16) +((cmph_uint32)k[3]<<24));
+		hashes[1] += ((cmph_uint32)k[4] +((cmph_uint32)k[5]<<8) +((cmph_uint32)k[6]<<16) +((cmph_uint32)k[7]<<24));
+		hashes[2] += ((cmph_uint32)k[8] +((cmph_uint32)k[9]<<8) +((cmph_uint32)k[10]<<16)+((cmph_uint32)k[11]<<24));
+		mix(hashes[0],hashes[1],hashes[2]);
+		k += 12; len -= 12;
+	}
+
+	/*------------------------------------- handle the last 11 bytes */
+	hashes[2]  += length;
+	switch(len)              /* all the case statements fall through */
+	{
+		case 11: 
+			hashes[2] +=((cmph_uint32)k[10]<<24);
+		case 10: 
+			hashes[2] +=((cmph_uint32)k[9]<<16);
+		case 9 : 
+			hashes[2] +=((cmph_uint32)k[8]<<8);
+			/* the first byte of hashes[2] is reserved for the length */
+		case 8 : 
+			hashes[1] +=((cmph_uint32)k[7]<<24);
+		case 7 : 
+			hashes[1] +=((cmph_uint32)k[6]<<16);
+		case 6 : 
+			hashes[1] +=((cmph_uint32)k[5]<<8);
+		case 5 :
+			hashes[1] +=(cmph_uint8) k[4];
+		case 4 : 
+			hashes[0] +=((cmph_uint32)k[3]<<24);
+		case 3 : 
+			hashes[0] +=((cmph_uint32)k[2]<<16);
+		case 2 : 
+			hashes[0] +=((cmph_uint32)k[1]<<8);
+		case 1 : 
+			hashes[0] +=(cmph_uint8)k[0];
+			/* case 0: nothing left to add */
+	}
+
+	mix(hashes[0],hashes[1],hashes[2]);
+}
+
+cmph_uint32 jenkins_hash(jenkins_state_t *state, const char *k, cmph_uint32 keylen)
+{
+	cmph_uint32 hashes[3];
+	__jenkins_hash_vector(state->seed, k, keylen, hashes);
+	return hashes[2];
+/*	cmph_uint32 a, b, c;
+	cmph_uint32 len, length;
+
+	// Set up the internal state 
+	length = keylen;
+	len = length;
+	a = b = 0x9e3779b9;  // the golden ratio; an arbitrary value 
+	c = state->seed;   // the previous hash value - seed in our case 
+
+	// handle most of the key 
+	while (len >= 12)
+	{
+		a += (k[0] +((cmph_uint32)k[1]<<8) +((cmph_uint32)k[2]<<16) +((cmph_uint32)k[3]<<24));
+		b += (k[4] +((cmph_uint32)k[5]<<8) +((cmph_uint32)k[6]<<16) +((cmph_uint32)k[7]<<24));
+		c += (k[8] +((cmph_uint32)k[9]<<8) +((cmph_uint32)k[10]<<16)+((cmph_uint32)k[11]<<24));
+		mix(a,b,c);
+		k += 12; len -= 12;
+	}
+
+	// handle the last 11 bytes
+	c  += length;
+	switch(len)              /// all the case statements fall through 
+	{
+		case 11: 
+			c +=((cmph_uint32)k[10]<<24);
+		case 10: 
+			c +=((cmph_uint32)k[9]<<16);
+		case 9 : 
+			c +=((cmph_uint32)k[8]<<8);
+			// the first byte of c is reserved for the length 
+		case 8 : 
+			b +=((cmph_uint32)k[7]<<24);
+		case 7 : 
+			b +=((cmph_uint32)k[6]<<16);
+		case 6 : 
+			b +=((cmph_uint32)k[5]<<8);
+		case 5 : 
+			b +=k[4];
+		case 4 : 
+			a +=((cmph_uint32)k[3]<<24);
+		case 3 : 
+			a +=((cmph_uint32)k[2]<<16);
+		case 2 : 
+			a +=((cmph_uint32)k[1]<<8);
+		case 1 : 
+			a +=k[0];
+		// case 0: nothing left to add 
+	}
+
+	mix(a,b,c);
+
+	/// report the result 
+
+	return c;
+	*/
+}
+
+void jenkins_hash_vector_(jenkins_state_t *state, const char *k, cmph_uint32 keylen, cmph_uint32 * hashes)
+{
+	__jenkins_hash_vector(state->seed, k, keylen, hashes);
+}
+
+void jenkins_state_dump(jenkins_state_t *state, char **buf, cmph_uint32 *buflen)
+{
+	*buflen = sizeof(cmph_uint32);
+	*buf = (char *)malloc(sizeof(cmph_uint32));
+	if (!*buf) 
+	{
+		*buflen = UINT_MAX;
+		return;
+	}
+	memcpy(*buf, &(state->seed), sizeof(cmph_uint32));
+	DEBUGP("Dumped jenkins state with seed %u\n", state->seed);
+	return;
+}
+
+jenkins_state_t *jenkins_state_copy(jenkins_state_t *src_state)
+{
+	jenkins_state_t *dest_state = (jenkins_state_t *)malloc(sizeof(jenkins_state_t));
+	dest_state->hashfunc = src_state->hashfunc;
+	dest_state->seed = src_state->seed;
+	return dest_state;
+}
+
+jenkins_state_t *jenkins_state_load(const char *buf, cmph_uint32 buflen)
+{
+	jenkins_state_t *state = (jenkins_state_t *)malloc(sizeof(jenkins_state_t));
+	state->seed = *(cmph_uint32 *)buf;
+	state->hashfunc = CMPH_HASH_JENKINS;
+	DEBUGP("Loaded jenkins state with seed %u\n", state->seed);
+	return state;
+}
+
+
+/** \fn void jenkins_state_pack(jenkins_state_t *state, void *jenkins_packed);
+ *  \brief Support the ability to pack a jenkins function into a preallocated contiguous memory space pointed by jenkins_packed.
+ *  \param state points to the jenkins function
+ *  \param jenkins_packed pointer to the contiguous memory area used to store the jenkins function. The size of jenkins_packed must be at least jenkins_state_packed_size() 
+ */
+void jenkins_state_pack(jenkins_state_t *state, void *jenkins_packed)
+{
+	if (state && jenkins_packed)
+	{
+		memcpy(jenkins_packed, &(state->seed), sizeof(cmph_uint32));
+	}
+}
+
+/** \fn cmph_uint32 jenkins_state_packed_size(jenkins_state_t *state);
+ *  \brief Return the amount of space needed to pack a jenkins function.
+ *  \return the size of the packed function or zero for failures
+ */ 
+cmph_uint32 jenkins_state_packed_size()
+{
+	return sizeof(cmph_uint32);
+}
+
+
+/** \fn cmph_uint32 jenkins_hash_packed(void *jenkins_packed, const char *k, cmph_uint32 keylen);
+ *  \param jenkins_packed is a pointer to a contiguous memory area
+ *  \param key is a pointer to a key
+ *  \param keylen is the key length
+ *  \return an integer that represents a hash value of 32 bits.
+ */
+cmph_uint32 jenkins_hash_packed(void *jenkins_packed, const char *k, cmph_uint32 keylen)
+{
+	cmph_uint32 hashes[3];
+	__jenkins_hash_vector(*((cmph_uint32 *)jenkins_packed), k, keylen, hashes);
+	return hashes[2];
+}
+
+/** \fn jenkins_hash_vector_packed(void *jenkins_packed, const char *k, cmph_uint32 keylen, cmph_uint32 * hashes);
+ *  \param jenkins_packed is a pointer to a contiguous memory area
+ *  \param key is a pointer to a key
+ *  \param keylen is the key length
+ *  \param hashes is a pointer to a memory large enough to fit three 32-bit integers.
+ */
+void jenkins_hash_vector_packed(void *jenkins_packed, const char *k, cmph_uint32 keylen, cmph_uint32 * hashes)
+{
+	__jenkins_hash_vector(*((cmph_uint32 *)jenkins_packed), k, keylen, hashes);
+}
diff --git a/girepository/cmph/jenkins_hash.h b/girepository/cmph/jenkins_hash.h
new file mode 100644
index 0000000..8e8b917
--- /dev/null
+++ b/girepository/cmph/jenkins_hash.h
@@ -0,0 +1,65 @@
+#ifndef __JEKINS_HASH_H__
+#define __JEKINS_HASH_H__
+
+#include "hash.h"
+
+typedef struct __jenkins_state_t
+{
+	CMPH_HASH hashfunc;
+	cmph_uint32 seed;
+} jenkins_state_t;
+	
+jenkins_state_t *jenkins_state_new(cmph_uint32 size); //size of hash table
+
+/** \fn cmph_uint32 jenkins_hash(jenkins_state_t *state, const char *k, cmph_uint32 keylen);
+ *  \param state is a pointer to a jenkins_state_t structure
+ *  \param key is a pointer to a key
+ *  \param keylen is the key length
+ *  \return an integer that represents a hash value of 32 bits.
+ */
+cmph_uint32 jenkins_hash(jenkins_state_t *state, const char *k, cmph_uint32 keylen);
+
+/** \fn void jenkins_hash_vector_(jenkins_state_t *state, const char *k, cmph_uint32 keylen, cmph_uint32 * hashes);
+ *  \param state is a pointer to a jenkins_state_t structure
+ *  \param key is a pointer to a key
+ *  \param keylen is the key length
+ *  \param hashes is a pointer to a memory large enough to fit three 32-bit integers.
+ */
+void jenkins_hash_vector_(jenkins_state_t *state, const char *k, cmph_uint32 keylen, cmph_uint32 * hashes);
+
+void jenkins_state_dump(jenkins_state_t *state, char **buf, cmph_uint32 *buflen);
+jenkins_state_t *jenkins_state_copy(jenkins_state_t *src_state);
+jenkins_state_t *jenkins_state_load(const char *buf, cmph_uint32 buflen);
+void jenkins_state_destroy(jenkins_state_t *state);
+
+/** \fn void jenkins_state_pack(jenkins_state_t *state, void *jenkins_packed);
+ *  \brief Support the ability to pack a jenkins function into a preallocated contiguous memory space pointed by jenkins_packed.
+ *  \param state points to the jenkins function
+ *  \param jenkins_packed pointer to the contiguous memory area used to store the jenkins function. The size of jenkins_packed must be at least jenkins_state_packed_size() 
+ */
+void jenkins_state_pack(jenkins_state_t *state, void *jenkins_packed);
+
+/** \fn cmph_uint32 jenkins_state_packed_size();
+ *  \brief Return the amount of space needed to pack a jenkins function.
+ *  \return the size of the packed function or zero for failures
+ */ 
+cmph_uint32 jenkins_state_packed_size();
+
+
+/** \fn cmph_uint32 jenkins_hash_packed(void *jenkins_packed, const char *k, cmph_uint32 keylen);
+ *  \param jenkins_packed is a pointer to a contiguous memory area
+ *  \param key is a pointer to a key
+ *  \param keylen is the key length
+ *  \return an integer that represents a hash value of 32 bits.
+ */
+cmph_uint32 jenkins_hash_packed(void *jenkins_packed, const char *k, cmph_uint32 keylen);
+
+/** \fn jenkins_hash_vector_packed(void *jenkins_packed, const char *k, cmph_uint32 keylen, cmph_uint32 * hashes);
+ *  \param jenkins_packed is a pointer to a contiguous memory area
+ *  \param key is a pointer to a key
+ *  \param keylen is the key length
+ *  \param hashes is a pointer to a memory large enough to fit three 32-bit integers.
+ */
+void jenkins_hash_vector_packed(void *jenkins_packed, const char *k, cmph_uint32 keylen, cmph_uint32 * hashes);
+
+#endif
diff --git a/girepository/cmph/main.c b/girepository/cmph/main.c
new file mode 100644
index 0000000..f739b32
--- /dev/null
+++ b/girepository/cmph/main.c
@@ -0,0 +1,342 @@
+#ifdef WIN32
+#include "wingetopt.h"
+#else
+#include <getopt.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <time.h>
+#include <limits.h>
+#include <assert.h>
+#include "cmph.h"
+#include "hash.h"
+
+#ifdef WIN32
+#define VERSION "0.8"
+#else
+#include "config.h"
+#endif
+
+
+void usage(const char *prg)
+{
+	fprintf(stderr, "usage: %s [-v] [-h] [-V] [-k nkeys] [-f hash_function] [-g [-c algorithm_dependent_value][-s seed] ] [-a algorithm] [-M memory_in_MB] [-b algorithm_dependent_value] [-t keys_per_bin] [-d tmp_dir] [-m file.mph]  keysfile\n", prg);   
+}
+void usage_long(const char *prg)
+{
+	cmph_uint32 i;
+	fprintf(stderr, "usage: %s [-v] [-h] [-V] [-k nkeys] [-f hash_function] [-g [-c algorithm_dependent_value][-s seed] ] [-a algorithm] [-M memory_in_MB] [-b algorithm_dependent_value] [-t keys_per_bin] [-d tmp_dir] [-m file.mph] keysfile\n", prg);   
+	fprintf(stderr, "Minimum perfect hashing tool\n\n"); 
+	fprintf(stderr, "  -h\t print this help message\n");
+	fprintf(stderr, "  -c\t c value determines:\n");
+	fprintf(stderr, "    \t  * the number of vertices in the graph for the algorithms BMZ and CHM\n");
+	fprintf(stderr, "    \t  * the number of bits per key required in the FCH algorithm\n");
+	fprintf(stderr, "    \t  * the load factor in the CHD_PH algorithm\n");
+	fprintf(stderr, "  -a\t algorithm - valid values are\n");
+	for (i = 0; i < CMPH_COUNT; ++i) fprintf(stderr, "    \t  * %s\n", cmph_names[i]);
+	fprintf(stderr, "  -f\t hash function (may be used multiple times) - valid values are\n");
+	for (i = 0; i < CMPH_HASH_COUNT; ++i) fprintf(stderr, "    \t  * %s\n", cmph_hash_names[i]);
+	fprintf(stderr, "  -V\t print version number and exit\n");
+	fprintf(stderr, "  -v\t increase verbosity (may be used multiple times)\n");
+	fprintf(stderr, "  -k\t number of keys\n");
+	fprintf(stderr, "  -g\t generation mode\n");
+	fprintf(stderr, "  -s\t random seed\n");
+	fprintf(stderr, "  -m\t minimum perfect hash function file \n");
+	fprintf(stderr, "  -M\t main memory availability (in MB) used in BRZ algorithm \n");
+	fprintf(stderr, "  -d\t temporary directory used in BRZ algorithm \n");
+	fprintf(stderr, "  -b\t the meaning of this parameter depends on the algorithm selected in the -a option:\n");
+	fprintf(stderr, "    \t  * For BRZ it is used to make the maximal number of keys in a bucket lower than 256.\n");
+	fprintf(stderr, "    \t    In this case its value should be an integer in the range [64,175]. Default is 128.\n\n");
+	fprintf(stderr, "    \t  * For BDZ it is used to determine the size of some precomputed rank\n");
+	fprintf(stderr, "    \t    information and its value should be an integer in the range [3,10]. Default\n");
+	fprintf(stderr, "    \t    is 7. The larger is this value, the more compact are the resulting functions\n");
+	fprintf(stderr, "    \t    and the slower are them at evaluation time.\n\n");
+	fprintf(stderr, "    \t  * For CHD and CHD_PH it is used to set the average number of keys per bucket\n");
+	fprintf(stderr, "    \t    and its value should be an integer in the range [1,32]. Default is 4. The\n");
+	fprintf(stderr, "    \t    larger is this value, the slower is the construction of the functions.\n");
+	fprintf(stderr, "    \t    This parameter has no effect for other algorithms.\n\n");
+	fprintf(stderr, "  -t\t set the number of keys per bin for a t-perfect hashing function. A t-perfect\n");	
+	fprintf(stderr, "    \t hash function allows at most t collisions in a given bin. This parameter applies\n");
+	fprintf(stderr, "    \t only to the CHD and CHD_PH algorithms. Its value should be an integer in the\n");
+	fprintf(stderr, "    \t range [1,128]. Defaul is 1\n");
+	fprintf(stderr, "  keysfile\t line separated file with keys\n");
+}
+
+int main(int argc, char **argv)
+{
+	cmph_uint32 verbosity = 0;
+	char generate = 0;
+	char *mphf_file = NULL;
+	FILE *mphf_fd = stdout;
+	const char *keys_file = NULL;
+	FILE *keys_fd;
+	cmph_uint32 nkeys = UINT_MAX;
+	cmph_uint32 seed = UINT_MAX;
+	CMPH_HASH *hashes = NULL;
+	cmph_uint32 nhashes = 0;
+	cmph_uint32 i;
+	CMPH_ALGO mph_algo = CMPH_CHM;
+	double c = 0;
+	cmph_config_t *config = NULL;
+	cmph_t *mphf = NULL;
+	char * tmp_dir = NULL;
+	cmph_io_adapter_t *source;
+	cmph_uint32 memory_availability = 0;
+	cmph_uint32 b = 0;
+	cmph_uint32 keys_per_bin = 1;
+	while (1)
+	{
+		char ch = (char)getopt(argc, argv, "hVvgc:k:a:M:b:t:f:m:d:s:");
+		if (ch == -1) break;
+		switch (ch)
+		{
+			case 's':
+				{
+					char *cptr;
+					seed = (cmph_uint32)strtoul(optarg, &cptr, 10);
+					if(*cptr != 0) {
+						fprintf(stderr, "Invalid seed %s\n", optarg);
+						exit(1);
+					}
+				}
+				break;
+			case 'c':
+				{
+					char *endptr;
+					c = strtod(optarg, &endptr);
+					if(*endptr != 0) {
+						fprintf(stderr, "Invalid c value %s\n", optarg);
+						exit(1);
+					}
+				}
+				break;
+			case 'g':
+				generate = 1;
+				break;
+			case 'k':
+			        {
+					char *endptr;
+					nkeys = (cmph_uint32)strtoul(optarg, &endptr, 10);
+					if(*endptr != 0) {
+						fprintf(stderr, "Invalid number of keys %s\n", optarg);
+						exit(1);
+					}
+				}
+				break;
+			case 'm':
+				mphf_file = strdup(optarg);
+				break;
+			case 'd':
+				tmp_dir = strdup(optarg);
+				break;
+			case 'M':
+				{
+					char *cptr;
+					memory_availability = (cmph_uint32)strtoul(optarg, &cptr, 10);
+					if(*cptr != 0) {
+						fprintf(stderr, "Invalid memory availability %s\n", optarg);
+						exit(1);
+					}
+				}
+				break;
+			case 'b':
+				{
+					char *cptr;
+					b =  (cmph_uint32)strtoul(optarg, &cptr, 10);
+					if(*cptr != 0) {
+						fprintf(stderr, "Parameter b was not found: %s\n", optarg);
+						exit(1);
+					}
+				}
+				break;
+			case 't':
+				{
+					char *cptr;
+					keys_per_bin = (cmph_uint32)strtoul(optarg, &cptr, 10);
+					if(*cptr != 0) {
+						fprintf(stderr, "Parameter t was not found: %s\n", optarg);
+						exit(1);
+					}
+				}
+				break;
+			case 'v':
+				++verbosity;
+				break;
+			case 'V':
+				printf("%s\n", VERSION);
+				return 0;
+			case 'h':
+				usage_long(argv[0]);
+				return 0;
+			case 'a':
+				{
+				char valid = 0;
+				for (i = 0; i < CMPH_COUNT; ++i)
+				{
+					if (strcmp(cmph_names[i], optarg) == 0)
+					{
+						mph_algo = i;
+						valid = 1;
+						break;
+					}
+				}
+				if (!valid) 
+				{
+					fprintf(stderr, "Invalid mph algorithm: %s. It is not available in version %s\n", optarg, VERSION);
+					return -1;
+				}
+				}
+				break;
+			case 'f':
+				{
+				char valid = 0;
+				for (i = 0; i < CMPH_HASH_COUNT; ++i)
+				{
+					if (strcmp(cmph_hash_names[i], optarg) == 0)
+					{
+						hashes = (CMPH_HASH *)realloc(hashes, sizeof(CMPH_HASH) * ( nhashes + 2 ));
+						hashes[nhashes] = i;
+						hashes[nhashes + 1] = CMPH_HASH_COUNT;
+						++nhashes;
+						valid = 1;
+						break;
+					}
+				}
+				if (!valid) 
+				{
+					fprintf(stderr, "Invalid hash function: %s\n", optarg);
+					return -1;
+				}
+				}
+				break;
+			default:
+				usage(argv[0]);
+				return 1;
+		}
+	}
+
+	if (optind != argc - 1)
+	{
+		usage(argv[0]);
+		return 1;
+	}
+	keys_file = argv[optind];
+  
+	if (seed == UINT_MAX) seed = (cmph_uint32)time(NULL);
+	srand(seed);
+	int ret = 0;
+	if (mphf_file == NULL)
+	{
+		mphf_file = (char *)malloc(strlen(keys_file) + 5);
+		memcpy(mphf_file, keys_file, strlen(keys_file));
+		memcpy(mphf_file + strlen(keys_file), ".mph\0", (size_t)5);
+	}	
+
+	keys_fd = fopen(keys_file, "r");
+
+	if (keys_fd == NULL)
+	{
+		fprintf(stderr, "Unable to open file %s: %s\n", keys_file, strerror(errno));
+		return -1;
+	}
+
+	if (seed == UINT_MAX) seed = (cmph_uint32)time(NULL);
+	if(nkeys == UINT_MAX) source = cmph_io_nlfile_adapter(keys_fd);
+	else source = cmph_io_nlnkfile_adapter(keys_fd, nkeys);
+	if (generate)
+	{
+		//Create mphf
+		mphf_fd = fopen(mphf_file, "w");
+		config = cmph_config_new(source);
+		cmph_config_set_algo(config, mph_algo);
+		if (nhashes) cmph_config_set_hashfuncs(config, hashes);
+		cmph_config_set_verbosity(config, verbosity);
+		cmph_config_set_tmp_dir(config, (cmph_uint8 *) tmp_dir);
+		cmph_config_set_mphf_fd(config, mphf_fd);
+		cmph_config_set_memory_availability(config, memory_availability);
+		cmph_config_set_b(config, b);
+		cmph_config_set_keys_per_bin(config, keys_per_bin);
+		
+		//if((mph_algo == CMPH_BMZ || mph_algo == CMPH_BRZ) && c >= 2.0) c=1.15;
+		if(mph_algo == CMPH_BMZ  && c >= 2.0) c=1.15;
+		if (c != 0) cmph_config_set_graphsize(config, c);
+		mphf = cmph_new(config);
+
+		cmph_config_destroy(config);
+		if (mphf == NULL)
+		{
+			fprintf(stderr, "Unable to create minimum perfect hashing function\n");
+			//cmph_config_destroy(config);
+			free(mphf_file);
+			return -1;
+		}
+
+		if (mphf_fd == NULL)
+		{
+			fprintf(stderr, "Unable to open output file %s: %s\n", mphf_file, strerror(errno));
+			free(mphf_file);
+			return -1;
+		}
+		cmph_dump(mphf, mphf_fd); 
+		cmph_destroy(mphf);	
+		fclose(mphf_fd);
+	}
+	else
+	{
+		cmph_uint8 * hashtable = NULL;
+		mphf_fd = fopen(mphf_file, "r");
+		if (mphf_fd == NULL)
+		{
+			fprintf(stderr, "Unable to open input file %s: %s\n", mphf_file, strerror(errno));
+			free(mphf_file);
+			return -1;
+		}
+		mphf = cmph_load(mphf_fd);
+		fclose(mphf_fd);
+		if (!mphf)
+		{
+			fprintf(stderr, "Unable to parser input file %s\n", mphf_file);
+			free(mphf_file);
+			return -1;
+		}
+		cmph_uint32 siz = cmph_size(mphf);
+		hashtable = (cmph_uint8*)calloc(siz, sizeof(cmph_uint8));
+		memset(hashtable, 0,(size_t) siz);
+		//check all keys
+		for (i = 0; i < source->nkeys; ++i)
+		{
+			cmph_uint32 h;
+			char *buf;
+			cmph_uint32 buflen = 0;
+			source->read(source->data, &buf, &buflen);
+			h = cmph_search(mphf, buf, buflen);
+			if (!(h < siz))
+			{
+				fprintf(stderr, "Unknown key %*s in the input.\n", buflen, buf);
+				ret = 1;
+			} else if(hashtable[h] >= keys_per_bin)
+			{
+				fprintf(stderr, "More than %u keys were mapped to bin %u\n", keys_per_bin, h);
+				fprintf(stderr, "Duplicated or unknown key %*s in the input\n", buflen, buf);
+				ret = 1;
+			} else hashtable[h]++;
+
+			if (verbosity)
+			{
+				printf("%s -> %u\n", buf, h);
+			}
+			source->dispose(source->data, buf, buflen);
+		}
+		
+		cmph_destroy(mphf);
+		free(hashtable);
+	}
+	fclose(keys_fd);
+	free(mphf_file);
+	free(tmp_dir);
+        cmph_io_nlfile_adapter_destroy(source);
+	return ret;
+  
+}
diff --git a/girepository/cmph/miller_rabin.c b/girepository/cmph/miller_rabin.c
new file mode 100644
index 0000000..17d0ed3
--- /dev/null
+++ b/girepository/cmph/miller_rabin.c
@@ -0,0 +1,67 @@
+#include "miller_rabin.h"
+
+static inline cmph_uint64 int_pow(cmph_uint64 a, cmph_uint64 d, cmph_uint64 n)
+{
+	cmph_uint64 a_pow = a;
+	cmph_uint64 res = 1;
+	while(d > 0)
+	{
+		if((d & 1) == 1)
+			res =(((cmph_uint64)res) * a_pow) % n;
+		a_pow = (((cmph_uint64)a_pow) * a_pow) % n;
+		d /= 2;
+	};
+	return res;
+};
+
+static inline cmph_uint8 check_witness(cmph_uint64 a_exp_d, cmph_uint64 n, cmph_uint64 s)
+{
+	cmph_uint64 i;
+	cmph_uint64 a_exp = a_exp_d;
+	if(a_exp == 1 || a_exp == (n - 1))
+		return 1;
+	for(i = 1; i < s; i++)
+	{
+		a_exp = (((cmph_uint64)a_exp) * a_exp) % n;
+		if(a_exp == (n - 1))
+			return 1;
+	};
+	return 0;
+};
+
+cmph_uint8 check_primality(cmph_uint64 n)
+{
+	cmph_uint64 a, d, s, a_exp_d;
+	if((n % 2) == 0)
+		return 0;
+	if((n % 3) == 0)
+		return 0;
+	if((n % 5) == 0)
+		return 0;
+	if((n % 7 ) == 0)
+		return 0;
+	//we decompoe the number n - 1 into 2^s*d
+	s = 0;
+	d = n - 1;
+	do 
+	{
+		s++;
+		d /= 2;
+	}while((d % 2) == 0);
+
+	a = 2;
+	a_exp_d = int_pow(a, d, n);
+	if(check_witness(a_exp_d, n, s) == 0)
+		return 0;
+	a = 7;
+	a_exp_d = int_pow(a, d, n);
+	if(check_witness(a_exp_d, n, s) == 0)
+		return 0;
+	a = 61;
+	a_exp_d = int_pow(a, d, n);
+	if(check_witness(a_exp_d, n, s) == 0)
+		return 0;
+	return 1;
+};
+
+
diff --git a/girepository/cmph/miller_rabin.h b/girepository/cmph/miller_rabin.h
new file mode 100644
index 0000000..42dc6ce
--- /dev/null
+++ b/girepository/cmph/miller_rabin.h
@@ -0,0 +1,5 @@
+#ifndef _CMPH_MILLER_RABIN_H__ 
+#define _CMPH_MILLER_RABIN_H__ 
+#include "cmph_types.h"
+cmph_uint8 check_primality(cmph_uint64 n);
+#endif
diff --git a/girepository/cmph/sdbm_hash.c b/girepository/cmph/sdbm_hash.c
new file mode 100644
index 0000000..2f706c9
--- /dev/null
+++ b/girepository/cmph/sdbm_hash.c
@@ -0,0 +1,49 @@
+#include "sdbm_hash.h"
+#include <stdlib.h>
+
+sdbm_state_t *sdbm_state_new()
+{
+	sdbm_state_t *state = (sdbm_state_t *)malloc(sizeof(sdbm_state_t));
+	state->hashfunc = CMPH_HASH_SDBM;
+	return state;
+}
+
+void sdbm_state_destroy(sdbm_state_t *state)
+{
+	free(state);
+}
+
+cmph_uint32 sdbm_hash(sdbm_state_t *state, const char *k, cmph_uint32 keylen)
+{
+	register cmph_uint32 hash = 0;
+	const unsigned char *ptr = (unsigned char *)k;
+	cmph_uint32 i = 0;
+
+	while(i < keylen) {
+		hash = *ptr + (hash << 6) + (hash << 16) - hash;
+		++ptr, ++i;
+	}
+	return hash;
+}
+
+
+void sdbm_state_dump(sdbm_state_t *state, char **buf, cmph_uint32 *buflen)
+{
+	*buf = NULL;
+	*buflen = 0;
+	return;
+}
+
+sdbm_state_t *sdbm_state_copy(sdbm_state_t *src_state)
+{
+	sdbm_state_t *dest_state = (sdbm_state_t *)malloc(sizeof(sdbm_state_t));
+	dest_state->hashfunc = src_state->hashfunc;
+	return dest_state;
+}
+
+sdbm_state_t *sdbm_state_load(const char *buf, cmph_uint32 buflen)
+{
+	sdbm_state_t *state = (sdbm_state_t *)malloc(sizeof(sdbm_state_t));
+	state->hashfunc = CMPH_HASH_SDBM;
+	return state;
+}
diff --git a/girepository/cmph/sdbm_hash.h b/girepository/cmph/sdbm_hash.h
new file mode 100644
index 0000000..f44b2f1
--- /dev/null
+++ b/girepository/cmph/sdbm_hash.h
@@ -0,0 +1,18 @@
+#ifndef __SDBM_HASH_H__
+#define __SDBM_HASH_H__
+
+#include "hash.h"
+
+typedef struct __sdbm_state_t
+{
+	CMPH_HASH hashfunc;
+} sdbm_state_t;
+
+sdbm_state_t *sdbm_state_new();
+cmph_uint32 sdbm_hash(sdbm_state_t *state, const char *k, cmph_uint32 keylen);
+void sdbm_state_dump(sdbm_state_t *state, char **buf, cmph_uint32 *buflen);
+sdbm_state_t *sdbm_state_copy(sdbm_state_t *src_state);
+sdbm_state_t *sdbm_state_load(const char *buf, cmph_uint32 buflen);
+void sdbm_state_destroy(sdbm_state_t *state);
+
+#endif
diff --git a/girepository/cmph/select.c b/girepository/cmph/select.c
new file mode 100644
index 0000000..fec4b7a
--- /dev/null
+++ b/girepository/cmph/select.c
@@ -0,0 +1,337 @@
+#include<stdlib.h>
+#include<stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <limits.h>
+#include "select_lookup_tables.h"
+#include "select.h"
+
+//#define DEBUG
+#include "debug.h"
+
+#ifndef STEP_SELECT_TABLE
+#define STEP_SELECT_TABLE 128
+#endif
+
+#ifndef NBITS_STEP_SELECT_TABLE
+#define NBITS_STEP_SELECT_TABLE 7
+#endif
+
+#ifndef MASK_STEP_SELECT_TABLE
+#define MASK_STEP_SELECT_TABLE 0x7f // 0x7f = 127
+#endif
+
+static inline void select_insert_0(cmph_uint32 * buffer)
+{
+	(*buffer) >>= 1;
+};
+
+static inline void select_insert_1(cmph_uint32 * buffer)
+{
+	(*buffer) >>= 1;
+	(*buffer) |= 0x80000000;
+};
+
+void select_init(select_t * sel)
+{
+	sel->n = 0;
+	sel->m = 0;
+	sel->bits_vec = 0;
+	sel->select_table = 0;
+};
+
+cmph_uint32 select_get_space_usage(select_t * sel)
+{
+	register cmph_uint32 nbits;
+	register cmph_uint32 vec_size;
+	register cmph_uint32 sel_table_size;
+	register cmph_uint32 space_usage;
+	
+	nbits = sel->n + sel->m;
+	vec_size = (nbits + 31) >> 5;
+	sel_table_size = (sel->n >> NBITS_STEP_SELECT_TABLE) + 1; // (sel->n >> NBITS_STEP_SELECT_TABLE) = (sel->n/STEP_SELECT_TABLE)
+
+	space_usage = 2 * sizeof(cmph_uint32) * 8; // n and m
+	space_usage += vec_size * (cmph_uint32) sizeof(cmph_uint32) * 8;
+	space_usage += sel_table_size * (cmph_uint32)sizeof(cmph_uint32) * 8;
+	return space_usage;
+}
+
+void select_destroy(select_t * sel)
+{
+	free(sel->bits_vec);
+	free(sel->select_table);
+	sel->bits_vec = 0;
+	sel->select_table = 0;
+};
+
+static inline void select_generate_sel_table(select_t * sel)
+{
+	register cmph_uint8 * bits_table = (cmph_uint8 *)sel->bits_vec;
+	register cmph_uint32 part_sum, old_part_sum;
+	register cmph_uint32 vec_idx, one_idx, sel_table_idx;
+	
+	part_sum = vec_idx = one_idx = sel_table_idx = 0;
+	
+	for(;;)
+	{
+	        // FABIANO: Should'n it be one_idx >= sel->n
+		if(one_idx >= sel->n)
+			break;
+		do 
+		{
+			old_part_sum = part_sum; 
+			part_sum += rank_lookup_table[bits_table[vec_idx]];
+			vec_idx++;
+		} while (part_sum <= one_idx);
+		
+		sel->select_table[sel_table_idx] = select_lookup_table[bits_table[vec_idx - 1]][one_idx - old_part_sum] + ((vec_idx - 1) << 3); // ((vec_idx - 1) << 3) = ((vec_idx - 1) * 8)
+		one_idx += STEP_SELECT_TABLE ;
+		sel_table_idx++;
+	};
+};
+
+void select_generate(select_t * sel, cmph_uint32 * keys_vec, cmph_uint32 n, cmph_uint32 m)
+{
+	register cmph_uint32 i, j, idx;
+	cmph_uint32 buffer = 0;
+	
+	register cmph_uint32 nbits;
+	register cmph_uint32 vec_size;
+	register cmph_uint32 sel_table_size;
+	sel->n = n;
+	sel->m = m; // n values in the range [0,m-1]
+	
+	nbits = sel->n + sel->m; 
+	vec_size = (nbits + 31) >> 5; // (nbits + 31) >> 5 = (nbits + 31)/32
+	
+	sel_table_size = (sel->n >> NBITS_STEP_SELECT_TABLE) + 1; // (sel->n >> NBITS_STEP_SELECT_TABLE) = (sel->n/STEP_SELECT_TABLE)
+	
+	if(sel->bits_vec)
+	{
+		free(sel->bits_vec);
+	}
+	sel->bits_vec = (cmph_uint32 *)calloc(vec_size, sizeof(cmph_uint32));
+
+	if(sel->select_table)
+	{
+		free(sel->select_table);
+	}
+	sel->select_table = (cmph_uint32 *)calloc(sel_table_size, sizeof(cmph_uint32));
+
+	
+	
+	idx = i = j = 0;
+	
+	for(;;)
+	{
+		while(keys_vec[j]==i)
+		{
+			select_insert_1(&buffer);
+			idx++;
+			
+			if((idx & 0x1f) == 0 ) // (idx & 0x1f) = idx % 32
+				sel->bits_vec[(idx >> 5) - 1] = buffer; // (idx >> 5) = idx/32
+			j++;
+			
+			if(j == sel->n)
+				goto loop_end;
+				
+			//assert(keys_vec[j] < keys_vec[j-1]);
+		}
+		
+		if(i == sel->m)
+			break;
+			
+		while(keys_vec[j] > i)
+		{
+			select_insert_0(&buffer);
+			idx++;
+			
+			if((idx & 0x1f) == 0 ) // (idx & 0x1f) = idx % 32
+				sel->bits_vec[(idx >> 5) - 1] = buffer; // (idx >> 5) = idx/32
+			i++;
+		};
+		
+	};
+	loop_end:
+	if((idx & 0x1f) != 0 ) // (idx & 0x1f) = idx % 32
+	{
+		buffer >>= 32 - (idx & 0x1f);
+		sel->bits_vec[ (idx - 1) >> 5 ] = buffer;
+	};
+	
+	select_generate_sel_table(sel);
+};
+
+static inline cmph_uint32 _select_query(cmph_uint8 * bits_table, cmph_uint32 * select_table, cmph_uint32 one_idx)
+{
+	register cmph_uint32 vec_bit_idx ,vec_byte_idx;
+	register cmph_uint32 part_sum, old_part_sum;
+	
+	vec_bit_idx = select_table[one_idx >> NBITS_STEP_SELECT_TABLE]; // one_idx >> NBITS_STEP_SELECT_TABLE = one_idx/STEP_SELECT_TABLE
+	vec_byte_idx = vec_bit_idx >> 3; // vec_bit_idx / 8
+	
+	one_idx &= MASK_STEP_SELECT_TABLE; // one_idx %= STEP_SELECT_TABLE == one_idx &= MASK_STEP_SELECT_TABLE
+	one_idx += rank_lookup_table[bits_table[vec_byte_idx] & ((1 << (vec_bit_idx & 0x7)) - 1)];
+	part_sum = 0;
+	
+	do
+	{
+		old_part_sum = part_sum; 
+		part_sum += rank_lookup_table[bits_table[vec_byte_idx]];
+		vec_byte_idx++;
+		
+	}while (part_sum <= one_idx);
+	
+	return select_lookup_table[bits_table[vec_byte_idx - 1]][one_idx - old_part_sum] + ((vec_byte_idx-1) << 3);
+}
+
+cmph_uint32 select_query(select_t * sel, cmph_uint32 one_idx)
+{
+	return _select_query((cmph_uint8 *)sel->bits_vec, sel->select_table, one_idx);
+};
+
+
+static inline cmph_uint32 _select_next_query(cmph_uint8 * bits_table, cmph_uint32 vec_bit_idx)
+{
+	register cmph_uint32 vec_byte_idx, one_idx;
+	register cmph_uint32 part_sum, old_part_sum;
+	
+	vec_byte_idx = vec_bit_idx >> 3;
+	
+	one_idx = rank_lookup_table[bits_table[vec_byte_idx] & ((1U << (vec_bit_idx & 0x7)) - 1U)] + 1U;
+	part_sum = 0;
+	
+	do
+	{
+		old_part_sum = part_sum; 
+		part_sum += rank_lookup_table[bits_table[vec_byte_idx]];
+		vec_byte_idx++;
+		
+	}while (part_sum <= one_idx);
+	
+	return select_lookup_table[bits_table[(vec_byte_idx - 1)]][(one_idx - old_part_sum)] + ((vec_byte_idx - 1) << 3);
+}
+
+cmph_uint32 select_next_query(select_t * sel, cmph_uint32 vec_bit_idx)
+{
+	return _select_next_query((cmph_uint8 *)sel->bits_vec, vec_bit_idx);
+};
+
+void select_dump(select_t *sel, char **buf, cmph_uint32 *buflen)
+{
+        register cmph_uint32 nbits = sel->n + sel->m;
+	register cmph_uint32 vec_size = ((nbits + 31) >> 5) * (cmph_uint32)sizeof(cmph_uint32); // (nbits + 31) >> 5 = (nbits + 31)/32
+	register cmph_uint32 sel_table_size = ((sel->n >> NBITS_STEP_SELECT_TABLE) + 1) * (cmph_uint32)sizeof(cmph_uint32); // (sel->n >> NBITS_STEP_SELECT_TABLE) = (sel->n/STEP_SELECT_TABLE)
+	register cmph_uint32 pos = 0;
+	
+	*buflen = 2*(cmph_uint32)sizeof(cmph_uint32) + vec_size + sel_table_size;
+	
+	*buf = (char *)calloc(*buflen, sizeof(char));
+	
+	if (!*buf) 
+	{
+		*buflen = UINT_MAX;
+		return;
+	}
+	
+	memcpy(*buf, &(sel->n), sizeof(cmph_uint32));
+	pos += (cmph_uint32)sizeof(cmph_uint32);
+	memcpy(*buf + pos, &(sel->m), sizeof(cmph_uint32));
+	pos += (cmph_uint32)sizeof(cmph_uint32);
+	memcpy(*buf + pos, sel->bits_vec, vec_size);
+	pos += vec_size;
+	memcpy(*buf + pos, sel->select_table, sel_table_size);
+
+	DEBUGP("Dumped select structure with size %u bytes\n", *buflen);
+}
+
+void select_load(select_t * sel, const char *buf, cmph_uint32 buflen)
+{
+	register cmph_uint32 pos = 0;
+        register cmph_uint32 nbits = 0;
+	register cmph_uint32 vec_size = 0;
+	register cmph_uint32 sel_table_size = 0;
+	
+	memcpy(&(sel->n), buf, sizeof(cmph_uint32));
+	pos += (cmph_uint32)sizeof(cmph_uint32);
+	memcpy(&(sel->m), buf + pos, sizeof(cmph_uint32));
+	pos += (cmph_uint32)sizeof(cmph_uint32);
+	
+	nbits = sel->n + sel->m;
+	vec_size = ((nbits + 31) >> 5) * (cmph_uint32)sizeof(cmph_uint32); // (nbits + 31) >> 5 = (nbits + 31)/32
+	sel_table_size = ((sel->n >> NBITS_STEP_SELECT_TABLE) + 1) * (cmph_uint32)sizeof(cmph_uint32); // (sel->n >> NBITS_STEP_SELECT_TABLE) = (sel->n/STEP_SELECT_TABLE)
+	
+	if(sel->bits_vec) 
+	{
+		free(sel->bits_vec);
+	}
+	sel->bits_vec = (cmph_uint32 *)calloc(vec_size/sizeof(cmph_uint32), sizeof(cmph_uint32));
+
+	if(sel->select_table) 
+	{
+		free(sel->select_table);
+	}
+	sel->select_table = (cmph_uint32 *)calloc(sel_table_size/sizeof(cmph_uint32), sizeof(cmph_uint32));
+
+	memcpy(sel->bits_vec, buf + pos, vec_size);
+	pos += vec_size;
+	memcpy(sel->select_table, buf + pos, sel_table_size);
+	
+	DEBUGP("Loaded select structure with size %u bytes\n", buflen);
+}
+
+
+/** \fn void select_pack(select_t *sel, void *sel_packed);
+ *  \brief Support the ability to pack a select structure function into a preallocated contiguous memory space pointed by sel_packed.
+ *  \param sel points to the select structure
+ *  \param sel_packed pointer to the contiguous memory area used to store the select structure. The size of sel_packed must be at least @see select_packed_size 
+ */
+void select_pack(select_t *sel, void *sel_packed)
+{
+	if (sel && sel_packed)
+	{
+		char *buf = NULL;
+		cmph_uint32 buflen = 0;
+		select_dump(sel, &buf, &buflen);
+		memcpy(sel_packed, buf, buflen);
+		free(buf);
+	}
+}
+
+
+/** \fn cmph_uint32 select_packed_size(select_t *sel);
+ *  \brief Return the amount of space needed to pack a select structure.
+ *  \return the size of the packed select structure or zero for failures
+ */ 
+cmph_uint32 select_packed_size(select_t *sel)
+{
+        register cmph_uint32 nbits = sel->n + sel->m;
+	register cmph_uint32 vec_size = ((nbits + 31) >> 5) * (cmph_uint32)sizeof(cmph_uint32); // (nbits + 31) >> 5 = (nbits + 31)/32
+	register cmph_uint32 sel_table_size = ((sel->n >> NBITS_STEP_SELECT_TABLE) + 1) * (cmph_uint32)sizeof(cmph_uint32); // (sel->n >> NBITS_STEP_SELECT_TABLE) = (sel->n/STEP_SELECT_TABLE)
+	return 2*(cmph_uint32)sizeof(cmph_uint32) + vec_size + sel_table_size;
+}
+
+
+
+cmph_uint32 select_query_packed(void * sel_packed, cmph_uint32 one_idx)
+{
+	register cmph_uint32 *ptr = (cmph_uint32 *)sel_packed;
+	register cmph_uint32 n = *ptr++;
+	register cmph_uint32 m = *ptr++;
+        register cmph_uint32 nbits = n + m;
+	register cmph_uint32 vec_size = (nbits + 31) >> 5; // (nbits + 31) >> 5 = (nbits + 31)/32
+	register cmph_uint8 * bits_vec = (cmph_uint8 *)ptr;
+	register cmph_uint32 * select_table = ptr + vec_size;
+	
+	return _select_query(bits_vec, select_table, one_idx);
+}
+
+
+cmph_uint32 select_next_query_packed(void * sel_packed, cmph_uint32 vec_bit_idx)
+{
+	register cmph_uint8 * bits_vec = (cmph_uint8 *)sel_packed;
+	bits_vec += 8; // skipping n and m
+	return _select_next_query(bits_vec, vec_bit_idx);
+}
diff --git a/girepository/cmph/select.h b/girepository/cmph/select.h
new file mode 100644
index 0000000..a31eb0f
--- /dev/null
+++ b/girepository/cmph/select.h
@@ -0,0 +1,61 @@
+#ifndef __CMPH_SELECT_H__
+#define __CMPH_SELECT_H__
+
+#include "cmph_types.h"
+
+struct _select_t
+{
+	cmph_uint32 n,m;
+	cmph_uint32 * bits_vec;
+	cmph_uint32 * select_table;
+};
+
+typedef struct _select_t select_t;
+
+void select_init(select_t * sel);
+
+void select_destroy(select_t * sel);
+ 
+void select_generate(select_t * sel, cmph_uint32 * keys_vec, cmph_uint32 n, cmph_uint32 m);
+
+cmph_uint32 select_query(select_t * sel, cmph_uint32 one_idx);
+
+cmph_uint32 select_next_query(select_t * sel, cmph_uint32 vec_bit_idx);
+
+cmph_uint32 select_get_space_usage(select_t * sel);
+
+void select_dump(select_t *sel, char **buf, cmph_uint32 *buflen);
+
+void select_load(select_t * sel, const char *buf, cmph_uint32 buflen);
+
+
+/** \fn void select_pack(select_t *sel, void *sel_packed);
+ *  \brief Support the ability to pack a select structure into a preallocated contiguous memory space pointed by sel_packed.
+ *  \param sel points to the select structure
+ *  \param sel_packed pointer to the contiguous memory area used to store the select structure. The size of sel_packed must be at least @see select_packed_size 
+ */
+void select_pack(select_t *sel, void *sel_packed);
+
+/** \fn cmph_uint32 select_packed_size(select_t *sel);
+ *  \brief Return the amount of space needed to pack a select structure.
+ *  \return the size of the packed select structure or zero for failures
+ */ 
+cmph_uint32 select_packed_size(select_t *sel);
+
+
+/** \fn cmph_uint32 select_query_packed(void * sel_packed, cmph_uint32 one_idx);
+ *  \param sel_packed is a pointer to a contiguous memory area
+ *  \param one_idx is the rank for which we want to calculate the inverse function select
+ *  \return an integer that represents the select value of rank idx.
+ */
+cmph_uint32 select_query_packed(void * sel_packed, cmph_uint32 one_idx);
+
+
+/** \fn cmph_uint32 select_next_query_packed(void * sel_packed, cmph_uint32 vec_bit_idx);
+ *  \param sel_packed is a pointer to a contiguous memory area
+ *  \param vec_bit_idx is a value prior computed by @see select_query_packed
+ *  \return an integer that represents the next select value greater than @see vec_bit_idx.
+ */
+cmph_uint32 select_next_query_packed(void * sel_packed, cmph_uint32 vec_bit_idx);
+
+#endif
diff --git a/girepository/cmph/select_lookup_tables.h b/girepository/cmph/select_lookup_tables.h
new file mode 100644
index 0000000..efd595e
--- /dev/null
+++ b/girepository/cmph/select_lookup_tables.h
@@ -0,0 +1,170 @@
+#ifndef SELECT_LOOKUP_TABLES
+#define SELECT_LOOKUP_TABLES
+
+#include "cmph_types.h"
+
+/*
+rank_lookup_table[i] simply gives the number of bits set to one in the byte of value i.
+For example if i = 01010101 in binary then we have :
+rank_lookup_table[i] = 4
+*/
+
+static cmph_uint8 rank_lookup_table[256] ={
+   0 , 1 , 1 , 2 , 1 , 2 , 2 , 3 , 1 , 2 , 2 , 3 , 2 , 3 , 3 , 4
+,  1 , 2 , 2 , 3 , 2 , 3 , 3 , 4 , 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5
+,  1 , 2 , 2 , 3 , 2 , 3 , 3 , 4 , 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5
+,  2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 , 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6
+,  1 , 2 , 2 , 3 , 2 , 3 , 3 , 4 , 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5
+,  2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 , 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6
+,  2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 , 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6
+,  3 , 4 , 4 , 5 , 4 , 5 , 5 , 6 , 4 , 5 , 5 , 6 , 5 , 6 , 6 , 7
+,  1 , 2 , 2 , 3 , 2 , 3 , 3 , 4 , 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5
+,  2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 , 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6
+,  2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 , 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6
+,  3 , 4 , 4 , 5 , 4 , 5 , 5 , 6 , 4 , 5 , 5 , 6 , 5 , 6 , 6 , 7
+,  2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 , 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6
+,  3 , 4 , 4 , 5 , 4 , 5 , 5 , 6 , 4 , 5 , 5 , 6 , 5 , 6 , 6 , 7
+,  3 , 4 , 4 , 5 , 4 , 5 , 5 , 6 , 4 , 5 , 5 , 6 , 5 , 6 , 6 , 7
+,  4 , 5 , 5 , 6 , 5 , 6 , 6 , 7 , 5 , 6 , 6 , 7 , 6 , 7 , 7 , 8 
+ };
+
+/*
+select_lookup_table[i][j] simply gives the index of the j'th bit set to one in the byte of value i.
+For example if i=01010101 in binary then we have :
+select_lookup_table[i][0] = 0,   the first bit set to one is at position 0
+select_lookup_table[i][1] = 2,   the second bit set to one is at position 2
+select_lookup_table[i][2] = 4,   the third bit set to one is at position 4
+select_lookup_table[i][3] = 6,   the fourth bit set to one is at position 6
+select_lookup_table[i][4] = 255, there is no more than 4 bits set to one in i, so we return escape value 255. 
+*/
+static cmph_uint8 select_lookup_table[256][8]={
+{ 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 255 , 255 , 255 , 255 , 255 , 255 , 255 } ,
+{ 1 , 255 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 255 , 255 , 255 , 255 , 255 , 255 } ,
+{ 2 , 255 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 2 , 255 , 255 , 255 , 255 , 255 , 255 } ,
+{ 1 , 2 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 2 , 255 , 255 , 255 , 255 , 255 } ,
+{ 3 , 255 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 3 , 255 , 255 , 255 , 255 , 255 , 255 } ,
+{ 1 , 3 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 3 , 255 , 255 , 255 , 255 , 255 } ,
+{ 2 , 3 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 2 , 3 , 255 , 255 , 255 , 255 , 255 } ,
+{ 1 , 2 , 3 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 2 , 3 , 255 , 255 , 255 , 255 } ,
+{ 4 , 255 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 4 , 255 , 255 , 255 , 255 , 255 , 255 } ,
+{ 1 , 4 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 4 , 255 , 255 , 255 , 255 , 255 } ,
+{ 2 , 4 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 2 , 4 , 255 , 255 , 255 , 255 , 255 } ,
+{ 1 , 2 , 4 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 2 , 4 , 255 , 255 , 255 , 255 } ,
+{ 3 , 4 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 3 , 4 , 255 , 255 , 255 , 255 , 255 } ,
+{ 1 , 3 , 4 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 3 , 4 , 255 , 255 , 255 , 255 } ,
+{ 2 , 3 , 4 , 255 , 255 , 255 , 255 , 255 } , { 0 , 2 , 3 , 4 , 255 , 255 , 255 , 255 } ,
+{ 1 , 2 , 3 , 4 , 255 , 255 , 255 , 255 } , { 0 , 1 , 2 , 3 , 4 , 255 , 255 , 255 } ,
+{ 5 , 255 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 5 , 255 , 255 , 255 , 255 , 255 , 255 } ,
+{ 1 , 5 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 5 , 255 , 255 , 255 , 255 , 255 } ,
+{ 2 , 5 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 2 , 5 , 255 , 255 , 255 , 255 , 255 } ,
+{ 1 , 2 , 5 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 2 , 5 , 255 , 255 , 255 , 255 } ,
+{ 3 , 5 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 3 , 5 , 255 , 255 , 255 , 255 , 255 } ,
+{ 1 , 3 , 5 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 3 , 5 , 255 , 255 , 255 , 255 } ,
+{ 2 , 3 , 5 , 255 , 255 , 255 , 255 , 255 } , { 0 , 2 , 3 , 5 , 255 , 255 , 255 , 255 } ,
+{ 1 , 2 , 3 , 5 , 255 , 255 , 255 , 255 } , { 0 , 1 , 2 , 3 , 5 , 255 , 255 , 255 } ,
+{ 4 , 5 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 4 , 5 , 255 , 255 , 255 , 255 , 255 } ,
+{ 1 , 4 , 5 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 4 , 5 , 255 , 255 , 255 , 255 } ,
+{ 2 , 4 , 5 , 255 , 255 , 255 , 255 , 255 } , { 0 , 2 , 4 , 5 , 255 , 255 , 255 , 255 } ,
+{ 1 , 2 , 4 , 5 , 255 , 255 , 255 , 255 } , { 0 , 1 , 2 , 4 , 5 , 255 , 255 , 255 } ,
+{ 3 , 4 , 5 , 255 , 255 , 255 , 255 , 255 } , { 0 , 3 , 4 , 5 , 255 , 255 , 255 , 255 } ,
+{ 1 , 3 , 4 , 5 , 255 , 255 , 255 , 255 } , { 0 , 1 , 3 , 4 , 5 , 255 , 255 , 255 } ,
+{ 2 , 3 , 4 , 5 , 255 , 255 , 255 , 255 } , { 0 , 2 , 3 , 4 , 5 , 255 , 255 , 255 } ,
+{ 1 , 2 , 3 , 4 , 5 , 255 , 255 , 255 } , { 0 , 1 , 2 , 3 , 4 , 5 , 255 , 255 } ,
+{ 6 , 255 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 6 , 255 , 255 , 255 , 255 , 255 , 255 } ,
+{ 1 , 6 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 6 , 255 , 255 , 255 , 255 , 255 } ,
+{ 2 , 6 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 2 , 6 , 255 , 255 , 255 , 255 , 255 } ,
+{ 1 , 2 , 6 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 2 , 6 , 255 , 255 , 255 , 255 } ,
+{ 3 , 6 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 3 , 6 , 255 , 255 , 255 , 255 , 255 } ,
+{ 1 , 3 , 6 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 3 , 6 , 255 , 255 , 255 , 255 } ,
+{ 2 , 3 , 6 , 255 , 255 , 255 , 255 , 255 } , { 0 , 2 , 3 , 6 , 255 , 255 , 255 , 255 } ,
+{ 1 , 2 , 3 , 6 , 255 , 255 , 255 , 255 } , { 0 , 1 , 2 , 3 , 6 , 255 , 255 , 255 } ,
+{ 4 , 6 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 4 , 6 , 255 , 255 , 255 , 255 , 255 } ,
+{ 1 , 4 , 6 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 4 , 6 , 255 , 255 , 255 , 255 } ,
+{ 2 , 4 , 6 , 255 , 255 , 255 , 255 , 255 } , { 0 , 2 , 4 , 6 , 255 , 255 , 255 , 255 } ,
+{ 1 , 2 , 4 , 6 , 255 , 255 , 255 , 255 } , { 0 , 1 , 2 , 4 , 6 , 255 , 255 , 255 } ,
+{ 3 , 4 , 6 , 255 , 255 , 255 , 255 , 255 } , { 0 , 3 , 4 , 6 , 255 , 255 , 255 , 255 } ,
+{ 1 , 3 , 4 , 6 , 255 , 255 , 255 , 255 } , { 0 , 1 , 3 , 4 , 6 , 255 , 255 , 255 } ,
+{ 2 , 3 , 4 , 6 , 255 , 255 , 255 , 255 } , { 0 , 2 , 3 , 4 , 6 , 255 , 255 , 255 } ,
+{ 1 , 2 , 3 , 4 , 6 , 255 , 255 , 255 } , { 0 , 1 , 2 , 3 , 4 , 6 , 255 , 255 } ,
+{ 5 , 6 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 5 , 6 , 255 , 255 , 255 , 255 , 255 } ,
+{ 1 , 5 , 6 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 5 , 6 , 255 , 255 , 255 , 255 } ,
+{ 2 , 5 , 6 , 255 , 255 , 255 , 255 , 255 } , { 0 , 2 , 5 , 6 , 255 , 255 , 255 , 255 } ,
+{ 1 , 2 , 5 , 6 , 255 , 255 , 255 , 255 } , { 0 , 1 , 2 , 5 , 6 , 255 , 255 , 255 } ,
+{ 3 , 5 , 6 , 255 , 255 , 255 , 255 , 255 } , { 0 , 3 , 5 , 6 , 255 , 255 , 255 , 255 } ,
+{ 1 , 3 , 5 , 6 , 255 , 255 , 255 , 255 } , { 0 , 1 , 3 , 5 , 6 , 255 , 255 , 255 } ,
+{ 2 , 3 , 5 , 6 , 255 , 255 , 255 , 255 } , { 0 , 2 , 3 , 5 , 6 , 255 , 255 , 255 } ,
+{ 1 , 2 , 3 , 5 , 6 , 255 , 255 , 255 } , { 0 , 1 , 2 , 3 , 5 , 6 , 255 , 255 } ,
+{ 4 , 5 , 6 , 255 , 255 , 255 , 255 , 255 } , { 0 , 4 , 5 , 6 , 255 , 255 , 255 , 255 } ,
+{ 1 , 4 , 5 , 6 , 255 , 255 , 255 , 255 } , { 0 , 1 , 4 , 5 , 6 , 255 , 255 , 255 } ,
+{ 2 , 4 , 5 , 6 , 255 , 255 , 255 , 255 } , { 0 , 2 , 4 , 5 , 6 , 255 , 255 , 255 } ,
+{ 1 , 2 , 4 , 5 , 6 , 255 , 255 , 255 } , { 0 , 1 , 2 , 4 , 5 , 6 , 255 , 255 } ,
+{ 3 , 4 , 5 , 6 , 255 , 255 , 255 , 255 } , { 0 , 3 , 4 , 5 , 6 , 255 , 255 , 255 } ,
+{ 1 , 3 , 4 , 5 , 6 , 255 , 255 , 255 } , { 0 , 1 , 3 , 4 , 5 , 6 , 255 , 255 } ,
+{ 2 , 3 , 4 , 5 , 6 , 255 , 255 , 255 } , { 0 , 2 , 3 , 4 , 5 , 6 , 255 , 255 } ,
+{ 1 , 2 , 3 , 4 , 5 , 6 , 255 , 255 } , { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 255 } ,
+{ 7 , 255 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 7 , 255 , 255 , 255 , 255 , 255 , 255 } ,
+{ 1 , 7 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 7 , 255 , 255 , 255 , 255 , 255 } ,
+{ 2 , 7 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 2 , 7 , 255 , 255 , 255 , 255 , 255 } ,
+{ 1 , 2 , 7 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 2 , 7 , 255 , 255 , 255 , 255 } ,
+{ 3 , 7 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 3 , 7 , 255 , 255 , 255 , 255 , 255 } ,
+{ 1 , 3 , 7 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 3 , 7 , 255 , 255 , 255 , 255 } ,
+{ 2 , 3 , 7 , 255 , 255 , 255 , 255 , 255 } , { 0 , 2 , 3 , 7 , 255 , 255 , 255 , 255 } ,
+{ 1 , 2 , 3 , 7 , 255 , 255 , 255 , 255 } , { 0 , 1 , 2 , 3 , 7 , 255 , 255 , 255 } ,
+{ 4 , 7 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 4 , 7 , 255 , 255 , 255 , 255 , 255 } ,
+{ 1 , 4 , 7 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 4 , 7 , 255 , 255 , 255 , 255 } ,
+{ 2 , 4 , 7 , 255 , 255 , 255 , 255 , 255 } , { 0 , 2 , 4 , 7 , 255 , 255 , 255 , 255 } ,
+{ 1 , 2 , 4 , 7 , 255 , 255 , 255 , 255 } , { 0 , 1 , 2 , 4 , 7 , 255 , 255 , 255 } ,
+{ 3 , 4 , 7 , 255 , 255 , 255 , 255 , 255 } , { 0 , 3 , 4 , 7 , 255 , 255 , 255 , 255 } ,
+{ 1 , 3 , 4 , 7 , 255 , 255 , 255 , 255 } , { 0 , 1 , 3 , 4 , 7 , 255 , 255 , 255 } ,
+{ 2 , 3 , 4 , 7 , 255 , 255 , 255 , 255 } , { 0 , 2 , 3 , 4 , 7 , 255 , 255 , 255 } ,
+{ 1 , 2 , 3 , 4 , 7 , 255 , 255 , 255 } , { 0 , 1 , 2 , 3 , 4 , 7 , 255 , 255 } ,
+{ 5 , 7 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 5 , 7 , 255 , 255 , 255 , 255 , 255 } ,
+{ 1 , 5 , 7 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 5 , 7 , 255 , 255 , 255 , 255 } ,
+{ 2 , 5 , 7 , 255 , 255 , 255 , 255 , 255 } , { 0 , 2 , 5 , 7 , 255 , 255 , 255 , 255 } ,
+{ 1 , 2 , 5 , 7 , 255 , 255 , 255 , 255 } , { 0 , 1 , 2 , 5 , 7 , 255 , 255 , 255 } ,
+{ 3 , 5 , 7 , 255 , 255 , 255 , 255 , 255 } , { 0 , 3 , 5 , 7 , 255 , 255 , 255 , 255 } ,
+{ 1 , 3 , 5 , 7 , 255 , 255 , 255 , 255 } , { 0 , 1 , 3 , 5 , 7 , 255 , 255 , 255 } ,
+{ 2 , 3 , 5 , 7 , 255 , 255 , 255 , 255 } , { 0 , 2 , 3 , 5 , 7 , 255 , 255 , 255 } ,
+{ 1 , 2 , 3 , 5 , 7 , 255 , 255 , 255 } , { 0 , 1 , 2 , 3 , 5 , 7 , 255 , 255 } ,
+{ 4 , 5 , 7 , 255 , 255 , 255 , 255 , 255 } , { 0 , 4 , 5 , 7 , 255 , 255 , 255 , 255 } ,
+{ 1 , 4 , 5 , 7 , 255 , 255 , 255 , 255 } , { 0 , 1 , 4 , 5 , 7 , 255 , 255 , 255 } ,
+{ 2 , 4 , 5 , 7 , 255 , 255 , 255 , 255 } , { 0 , 2 , 4 , 5 , 7 , 255 , 255 , 255 } ,
+{ 1 , 2 , 4 , 5 , 7 , 255 , 255 , 255 } , { 0 , 1 , 2 , 4 , 5 , 7 , 255 , 255 } ,
+{ 3 , 4 , 5 , 7 , 255 , 255 , 255 , 255 } , { 0 , 3 , 4 , 5 , 7 , 255 , 255 , 255 } ,
+{ 1 , 3 , 4 , 5 , 7 , 255 , 255 , 255 } , { 0 , 1 , 3 , 4 , 5 , 7 , 255 , 255 } ,
+{ 2 , 3 , 4 , 5 , 7 , 255 , 255 , 255 } , { 0 , 2 , 3 , 4 , 5 , 7 , 255 , 255 } ,
+{ 1 , 2 , 3 , 4 , 5 , 7 , 255 , 255 } , { 0 , 1 , 2 , 3 , 4 , 5 , 7 , 255 } ,
+{ 6 , 7 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 6 , 7 , 255 , 255 , 255 , 255 , 255 } ,
+{ 1 , 6 , 7 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 6 , 7 , 255 , 255 , 255 , 255 } ,
+{ 2 , 6 , 7 , 255 , 255 , 255 , 255 , 255 } , { 0 , 2 , 6 , 7 , 255 , 255 , 255 , 255 } ,
+{ 1 , 2 , 6 , 7 , 255 , 255 , 255 , 255 } , { 0 , 1 , 2 , 6 , 7 , 255 , 255 , 255 } ,
+{ 3 , 6 , 7 , 255 , 255 , 255 , 255 , 255 } , { 0 , 3 , 6 , 7 , 255 , 255 , 255 , 255 } ,
+{ 1 , 3 , 6 , 7 , 255 , 255 , 255 , 255 } , { 0 , 1 , 3 , 6 , 7 , 255 , 255 , 255 } ,
+{ 2 , 3 , 6 , 7 , 255 , 255 , 255 , 255 } , { 0 , 2 , 3 , 6 , 7 , 255 , 255 , 255 } ,
+{ 1 , 2 , 3 , 6 , 7 , 255 , 255 , 255 } , { 0 , 1 , 2 , 3 , 6 , 7 , 255 , 255 } ,
+{ 4 , 6 , 7 , 255 , 255 , 255 , 255 , 255 } , { 0 , 4 , 6 , 7 , 255 , 255 , 255 , 255 } ,
+{ 1 , 4 , 6 , 7 , 255 , 255 , 255 , 255 } , { 0 , 1 , 4 , 6 , 7 , 255 , 255 , 255 } ,
+{ 2 , 4 , 6 , 7 , 255 , 255 , 255 , 255 } , { 0 , 2 , 4 , 6 , 7 , 255 , 255 , 255 } ,
+{ 1 , 2 , 4 , 6 , 7 , 255 , 255 , 255 } , { 0 , 1 , 2 , 4 , 6 , 7 , 255 , 255 } ,
+{ 3 , 4 , 6 , 7 , 255 , 255 , 255 , 255 } , { 0 , 3 , 4 , 6 , 7 , 255 , 255 , 255 } ,
+{ 1 , 3 , 4 , 6 , 7 , 255 , 255 , 255 } , { 0 , 1 , 3 , 4 , 6 , 7 , 255 , 255 } ,
+{ 2 , 3 , 4 , 6 , 7 , 255 , 255 , 255 } , { 0 , 2 , 3 , 4 , 6 , 7 , 255 , 255 } ,
+{ 1 , 2 , 3 , 4 , 6 , 7 , 255 , 255 } , { 0 , 1 , 2 , 3 , 4 , 6 , 7 , 255 } ,
+{ 5 , 6 , 7 , 255 , 255 , 255 , 255 , 255 } , { 0 , 5 , 6 , 7 , 255 , 255 , 255 , 255 } ,
+{ 1 , 5 , 6 , 7 , 255 , 255 , 255 , 255 } , { 0 , 1 , 5 , 6 , 7 , 255 , 255 , 255 } ,
+{ 2 , 5 , 6 , 7 , 255 , 255 , 255 , 255 } , { 0 , 2 , 5 , 6 , 7 , 255 , 255 , 255 } ,
+{ 1 , 2 , 5 , 6 , 7 , 255 , 255 , 255 } , { 0 , 1 , 2 , 5 , 6 , 7 , 255 , 255 } ,
+{ 3 , 5 , 6 , 7 , 255 , 255 , 255 , 255 } , { 0 , 3 , 5 , 6 , 7 , 255 , 255 , 255 } ,
+{ 1 , 3 , 5 , 6 , 7 , 255 , 255 , 255 } , { 0 , 1 , 3 , 5 , 6 , 7 , 255 , 255 } ,
+{ 2 , 3 , 5 , 6 , 7 , 255 , 255 , 255 } , { 0 , 2 , 3 , 5 , 6 , 7 , 255 , 255 } ,
+{ 1 , 2 , 3 , 5 , 6 , 7 , 255 , 255 } , { 0 , 1 , 2 , 3 , 5 , 6 , 7 , 255 } ,
+{ 4 , 5 , 6 , 7 , 255 , 255 , 255 , 255 } , { 0 , 4 , 5 , 6 , 7 , 255 , 255 , 255 } ,
+{ 1 , 4 , 5 , 6 , 7 , 255 , 255 , 255 } , { 0 , 1 , 4 , 5 , 6 , 7 , 255 , 255 } ,
+{ 2 , 4 , 5 , 6 , 7 , 255 , 255 , 255 } , { 0 , 2 , 4 , 5 , 6 , 7 , 255 , 255 } ,
+{ 1 , 2 , 4 , 5 , 6 , 7 , 255 , 255 } , { 0 , 1 , 2 , 4 , 5 , 6 , 7 , 255 } ,
+{ 3 , 4 , 5 , 6 , 7 , 255 , 255 , 255 } , { 0 , 3 , 4 , 5 , 6 , 7 , 255 , 255 } ,
+{ 1 , 3 , 4 , 5 , 6 , 7 , 255 , 255 } , { 0 , 1 , 3 , 4 , 5 , 6 , 7 , 255 } ,
+{ 2 , 3 , 4 , 5 , 6 , 7 , 255 , 255 } , { 0 , 2 , 3 , 4 , 5 , 6 , 7 , 255 } ,
+{ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 255 } , { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 } };
+
+#endif
diff --git a/girepository/cmph/vqueue.c b/girepository/cmph/vqueue.c
new file mode 100644
index 0000000..0619dd7
--- /dev/null
+++ b/girepository/cmph/vqueue.c
@@ -0,0 +1,51 @@
+#include "vqueue.h"
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+struct __vqueue_t
+{
+  cmph_uint32 * values;
+  cmph_uint32 beg, end, capacity;
+};
+
+vqueue_t * vqueue_new(cmph_uint32 capacity)
+{
+  size_t capacity_plus_one = capacity + 1;
+  vqueue_t *q = (vqueue_t *)malloc(sizeof(vqueue_t));
+  assert(q);
+  q->values = (cmph_uint32 *)calloc(capacity_plus_one, sizeof(cmph_uint32));
+  q->beg = q->end = 0;
+  q->capacity = (cmph_uint32) capacity_plus_one;
+  return q;
+}
+
+cmph_uint8 vqueue_is_empty(vqueue_t * q)
+{
+  return (cmph_uint8)(q->beg == q->end);
+}
+
+void vqueue_insert(vqueue_t * q, cmph_uint32 val)
+{
+  assert((q->end + 1)%q->capacity != q->beg); // Is queue full?
+  q->end = (q->end + 1)%q->capacity;
+  q->values[q->end] = val;
+}
+
+cmph_uint32 vqueue_remove(vqueue_t * q)
+{
+  assert(!vqueue_is_empty(q)); // Is queue empty?
+  q->beg = (q->beg + 1)%q->capacity;
+  return q->values[q->beg];
+}
+
+void vqueue_print(vqueue_t * q)
+{
+  cmph_uint32 i;
+  for (i = q->beg; i != q->end; i = (i + 1)%q->capacity)
+    fprintf(stderr, "%u\n", q->values[(i + 1)%q->capacity]);
+} 
+
+void vqueue_destroy(vqueue_t *q)
+{
+  free(q->values); q->values = NULL; free(q);
+}
diff --git a/girepository/cmph/vqueue.h b/girepository/cmph/vqueue.h
new file mode 100644
index 0000000..86fccab
--- /dev/null
+++ b/girepository/cmph/vqueue.h
@@ -0,0 +1,18 @@
+#ifndef __CMPH_VQUEUE_H__
+#define __CMPH_VQUEUE_H__
+
+#include "cmph_types.h"
+typedef struct __vqueue_t vqueue_t;
+
+vqueue_t * vqueue_new(cmph_uint32 capacity);
+
+cmph_uint8 vqueue_is_empty(vqueue_t * q);
+
+void vqueue_insert(vqueue_t * q, cmph_uint32 val);
+
+cmph_uint32 vqueue_remove(vqueue_t * q);
+
+void vqueue_print(vqueue_t * q);
+
+void vqueue_destroy(vqueue_t * q);
+#endif
diff --git a/girepository/cmph/vstack.c b/girepository/cmph/vstack.c
new file mode 100644
index 0000000..24555cd
--- /dev/null
+++ b/girepository/cmph/vstack.c
@@ -0,0 +1,79 @@
+#include "vstack.h"
+
+#include <stdlib.h>
+#include <assert.h>
+
+//#define DEBUG
+#include "debug.h"
+
+struct __vstack_t
+{
+	cmph_uint32 pointer;
+	cmph_uint32 *values;
+	cmph_uint32 capacity;
+};
+
+vstack_t *vstack_new()
+{
+	vstack_t *stack = (vstack_t *)malloc(sizeof(vstack_t));
+	assert(stack);
+	stack->pointer = 0;
+	stack->values = NULL;
+	stack->capacity = 0;
+	return stack;
+}
+
+void vstack_destroy(vstack_t *stack)
+{
+	assert(stack);
+	free(stack->values);
+	free(stack);
+}
+
+void vstack_push(vstack_t *stack, cmph_uint32 val)
+{
+	assert(stack);
+	vstack_reserve(stack, stack->pointer + 1);
+	stack->values[stack->pointer] = val;
+	++(stack->pointer);
+}
+void vstack_pop(vstack_t *stack)
+{
+	assert(stack);
+	assert(stack->pointer > 0);
+	--(stack->pointer);
+}
+
+cmph_uint32 vstack_top(vstack_t *stack)
+{
+	assert(stack);
+	assert(stack->pointer > 0);
+	return stack->values[(stack->pointer - 1)];
+}
+int vstack_empty(vstack_t *stack)
+{
+	assert(stack);
+	return stack->pointer == 0;
+}
+cmph_uint32 vstack_size(vstack_t *stack)
+{
+	return stack->pointer;
+}
+void vstack_reserve(vstack_t *stack, cmph_uint32 size)
+{
+	assert(stack);
+	if (stack->capacity < size)
+	{
+		cmph_uint32 new_capacity = stack->capacity + 1;
+		DEBUGP("Increasing current capacity %u to %u\n", stack->capacity, size);
+		while (new_capacity	< size)
+		{
+			new_capacity *= 2;
+		}
+		stack->values = (cmph_uint32 *)realloc(stack->values, sizeof(cmph_uint32)*new_capacity);
+		assert(stack->values);
+		stack->capacity = new_capacity;
+		DEBUGP("Increased\n");
+	}
+}
+		
diff --git a/girepository/cmph/vstack.h b/girepository/cmph/vstack.h
new file mode 100644
index 0000000..1cefaaf
--- /dev/null
+++ b/girepository/cmph/vstack.h
@@ -0,0 +1,18 @@
+#ifndef __CMPH_VSTACK_H__
+#define __CMPH_VSTACK_H__
+
+#include "cmph_types.h"
+typedef struct __vstack_t vstack_t;
+
+vstack_t *vstack_new();
+void vstack_destroy(vstack_t *stack);
+
+void vstack_push(vstack_t *stack, cmph_uint32 val);
+cmph_uint32 vstack_top(vstack_t *stack);
+void vstack_pop(vstack_t *stack);
+int vstack_empty(vstack_t *stack);
+cmph_uint32 vstack_size(vstack_t *stack);
+
+void vstack_reserve(vstack_t *stack, cmph_uint32 size);
+
+#endif
diff --git a/girepository/cmph/wingetopt.c b/girepository/cmph/wingetopt.c
new file mode 100644
index 0000000..c981d0f
--- /dev/null
+++ b/girepository/cmph/wingetopt.c
@@ -0,0 +1,179 @@
+#ifdef WIN32
+/***************************************************************************** 
+ * 
+ *  MODULE NAME : GETOPT.C 
+ * 
+ *  COPYRIGHTS: 
+ *             This module contains code made available by IBM 
+ *             Corporation on an AS IS basis.  Any one receiving the 
+ *             module is considered to be licensed under IBM copyrights 
+ *             to use the IBM-provided source code in any way he or she 
+ *             deems fit, including copying it, compiling it, modifying 
+ *             it, and redistributing it, with or without 
+ *             modifications.  No license under any IBM patents or 
+ *             patent applications is to be implied from this copyright 
+ *             license. 
+ * 
+ *             A user of the module should understand that IBM cannot 
+ *             provide technical support for the module and will not be 
+ *             responsible for any consequences of use of the program. 
+ * 
+ *             Any notices, including this one, are not to be removed 
+ *             from the module without the prior written consent of 
+ *             IBM. 
+ * 
+ *  AUTHOR:   Original author: 
+ *                 G. R. Blair (BOBBLAIR at AUSVM1) 
+ *                 Internet: bobblair bobblair austin ibm com 
+ * 
+ *            Extensively revised by: 
+ *                 John Q. Walker II, Ph.D. (JOHHQ at RALVM6) 
+ *                 Internet: johnq ralvm6 vnet ibm com 
+ * 
+ *****************************************************************************/ 
+ 
+/****************************************************************************** 
+ * getopt() 
+ * 
+ * The getopt() function is a command line parser.  It returns the next 
+ * option character in argv that matches an option character in opstring. 
+ * 
+ * The argv argument points to an array of argc+1 elements containing argc 
+ * pointers to character strings followed by a null pointer. 
+ * 
+ * The opstring argument points to a string of option characters; if an 
+ * option character is followed by a colon, the option is expected to have 
+ * an argument that may or may not be separated from it by white space. 
+ * The external variable optarg is set to point to the start of the option 
+ * argument on return from getopt(). 
+ * 
+ * The getopt() function places in optind the argv index of the next argument 
+ * to be processed.  The system initializes the external variable optind to 
+ * 1 before the first call to getopt(). 
+ * 
+ * When all options have been processed (that is, up to the first nonoption 
+ * argument), getopt() returns EOF.  The special option "--" may be used to 
+ * delimit the end of the options; EOF will be returned, and "--" will be 
+ * skipped. 
+ * 
+ * The getopt() function returns a question mark (?) when it encounters an 
+ * option character not included in opstring.  This error message can be 
+ * disabled by setting opterr to zero.  Otherwise, it returns the option 
+ * character that was detected. 
+ * 
+ * If the special option "--" is detected, or all options have been 
+ * processed, EOF is returned. 
+ * 
+ * Options are marked by either a minus sign (-) or a slash (/). 
+ * 
+ * No errors are defined. 
+ *****************************************************************************/ 
+
+#include <stdio.h>                  /* for EOF */ 
+#include <string.h>                 /* for strchr() */ 
+
+/* static (global) variables that are specified as exported by getopt() */ 
+extern char *optarg;    /* pointer to the start of the option argument  */ 
+extern int   optind;       /* number of the next argv[] to be evaluated    */ 
+extern int   opterr;       /* non-zero if a question mark should be returned 
+                           when a non-valid option character is detected */ 
+ 
+/* handle possible future character set concerns by putting this in a macro */ 
+#define _next_char(string)  (char)(*(string+1)) 
+ 
+int getopt(int argc, char *argv[], char *opstring) 
+{ 
+    static char *pIndexPosition = NULL; /* place inside current argv string */ 
+    char *pArgString = NULL;        /* where to start from next */ 
+    char *pOptString;               /* the string in our program */ 
+ 
+ 
+    if (pIndexPosition != NULL) { 
+        /* we last left off inside an argv string */ 
+        if (*(++pIndexPosition)) { 
+            /* there is more to come in the most recent argv */ 
+            pArgString = pIndexPosition; 
+        } 
+    } 
+ 
+    if (pArgString == NULL) { 
+        /* we didn't leave off in the middle of an argv string */ 
+        if (optind >= argc) { 
+            /* more command-line arguments than the argument count */ 
+            pIndexPosition = NULL;  /* not in the middle of anything */ 
+            return EOF;             /* used up all command-line arguments */ 
+        } 
+ 
+        /*--------------------------------------------------------------------- 
+         * If the next argv[] is not an option, there can be no more options. 
+         *-------------------------------------------------------------------*/ 
+        pArgString = argv[optind++]; /* set this to the next argument ptr */ 
+ 
+        if (('/' != *pArgString) && /* doesn't start with a slash or a dash? */ 
+            ('-' != *pArgString)) { 
+            --optind;               /* point to current arg once we're done */ 
+            optarg = NULL;          /* no argument follows the option */ 
+            pIndexPosition = NULL;  /* not in the middle of anything */ 
+            return EOF;             /* used up all the command-line flags */ 
+        } 
+ 
+        /* check for special end-of-flags markers */ 
+        if ((strcmp(pArgString, "-") == 0) || 
+            (strcmp(pArgString, "--") == 0)) { 
+            optarg = NULL;          /* no argument follows the option */ 
+            pIndexPosition = NULL;  /* not in the middle of anything */ 
+            return EOF;             /* encountered the special flag */ 
+        } 
+ 
+        pArgString++;               /* look past the / or - */ 
+    } 
+ 
+    if (':' == *pArgString) {       /* is it a colon? */ 
+        /*--------------------------------------------------------------------- 
+         * Rare case: if opterr is non-zero, return a question mark; 
+         * otherwise, just return the colon we're on. 
+         *-------------------------------------------------------------------*/ 
+        return (opterr ? (int)'?' : (int)':'); 
+    } 
+    else if ((pOptString = strchr(opstring, *pArgString)) == 0) { 
+        /*--------------------------------------------------------------------- 
+         * The letter on the command-line wasn't any good. 
+         *-------------------------------------------------------------------*/ 
+        optarg = NULL;              /* no argument follows the option */ 
+        pIndexPosition = NULL;      /* not in the middle of anything */ 
+        return (opterr ? (int)'?' : (int)*pArgString); 
+    } 
+    else { 
+        /*--------------------------------------------------------------------- 
+         * The letter on the command-line matches one we expect to see 
+         *-------------------------------------------------------------------*/ 
+        if (':' == _next_char(pOptString)) { /* is the next letter a colon? */ 
+            /* It is a colon.  Look for an argument string. */ 
+            if ('\0' != _next_char(pArgString)) {  /* argument in this argv? */ 
+                optarg = &pArgString[1];   /* Yes, it is */ 
+            } 
+            else { 
+                /*------------------------------------------------------------- 
+                 * The argument string must be in the next argv. 
+                 * But, what if there is none (bad input from the user)? 
+                 * In that case, return the letter, and optarg as NULL. 
+                 *-----------------------------------------------------------*/ 
+                if (optind < argc) 
+                    optarg = argv[optind++]; 
+                else { 
+                    optarg = NULL; 
+                    return (opterr ? (int)'?' : (int)*pArgString); 
+                } 
+            } 
+            pIndexPosition = NULL;  /* not in the middle of anything */ 
+        } 
+        else { 
+            /* it's not a colon, so just return the letter */ 
+            optarg = NULL;          /* no argument follows the option */ 
+            pIndexPosition = pArgString;    /* point to the letter we're on */ 
+        } 
+        return (int)*pArgString;    /* return the letter that matched */ 
+    } 
+} 
+
+#endif //WIN32
diff --git a/girepository/cmph/wingetopt.h b/girepository/cmph/wingetopt.h
new file mode 100644
index 0000000..9596853
--- /dev/null
+++ b/girepository/cmph/wingetopt.h
@@ -0,0 +1,25 @@
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef WIN32
+	#include <getopt.h>
+#else
+	#ifndef _GETOPT_
+	#define _GETOPT_
+
+	#include <stdio.h>                  /* for EOF */ 
+	#include <string.h>                 /* for strchr() */ 
+
+	char *optarg = NULL;    /* pointer to the start of the option argument  */ 
+	int   optind = 1;       /* number of the next argv[] to be evaluated    */ 
+	int   opterr = 1;       /* non-zero if a question mark should be returned */
+
+	int getopt(int argc, char *argv[], char *opstring); 
+	#endif //_GETOPT_
+#endif //WIN32
+
+#ifdef __cplusplus
+}
+#endif
+



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]