diff --git a/src/fr/inrialpes/exmo/align/impl/InstanceBasedMatrixMeasure.java b/src/fr/inrialpes/exmo/align/impl/InstanceBasedMatrixMeasure.java
new file mode 100644
index 0000000000000000000000000000000000000000..f11dce0bcacaedfca6534115ee67e90c07d42ac8
--- /dev/null
+++ b/src/fr/inrialpes/exmo/align/impl/InstanceBasedMatrixMeasure.java
@@ -0,0 +1,216 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) INRIA, 2010
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.  Authorship
+ * of the modifications may be determined from the ChangeLog placed at
+ * the end of this file.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA.
+ */
+
+package fr.inrialpes.exmo.align.impl; 
+
+// Alignment API classes
+import org.semanticweb.owl.align.Alignment;
+import org.semanticweb.owl.align.AlignmentException;
+
+// Alignment API implementation classes
+import fr.inrialpes.exmo.align.impl.MatrixMeasure;
+
+import fr.inrialpes.exmo.ontowrap.OntologyFactory;
+import fr.inrialpes.exmo.ontowrap.HeavyLoadedOntology;
+import fr.inrialpes.exmo.ontowrap.LoadedOntology;
+import fr.inrialpes.exmo.ontowrap.OntowrapException;
+
+// Java standard classes
+import java.util.Set;
+import java.util.Properties;
+import java.util.Vector;
+
+/**
+ * InstanceBasedMatrixMeasure
+ *
+ * This is a generic distance store in which
+ * - a distance between instances is computed and stored in the table
+ * - the classical distance between classes is computed from the distance between
+ *   instances through classical measure (linkage, etc.).
+ * - the rest is as usual
+ * 
+ * The only method to implement is computeInstanceDistance( params ).
+ * For additional flexibility, initialize( LoadedOntology onto1, LoadedOntology onto2, Alignment align ) can be refined.
+ * Note that it uses HeavyLoadedOntology.
+ *
+ */
+
+public abstract class InstanceBasedMatrixMeasure extends MatrixMeasure {
+
+    Set<Object>[] classinst1 = null;
+    Set<Object>[] classinst2 = null;
+
+    public InstanceBasedMatrixMeasure() {
+	similarity = false; // This is a distance
+    };
+
+    public void initialize( LoadedOntology onto1, LoadedOntology onto2, Alignment align ) {
+	// create the matrices and all structures
+	super.initialize( onto1, onto2, align );
+	try {
+	    if ( !(onto1 instanceof HeavyLoadedOntology) 
+		 || !(onto2 instanceof HeavyLoadedOntology) )
+		throw new AlignmentException( "InstanceBasedMatrixMeasure requires HeavyLoadedOntology");
+		HeavyLoadedOntology ontology1 = (HeavyLoadedOntology)onto1;
+		HeavyLoadedOntology ontology2 = (HeavyLoadedOntology)onto2;
+
+	    // Normalise class comparators (which instance belongs to which class)
+	    classinst1 = new Set[nbclass1];
+	    for( Object cl1 : ontology1.getClasses() ) {
+		classinst1[ classlist1.get( cl1 ).intValue() ] = ontology1.getInstances( cl1, OntologyFactory.LOCAL, OntologyFactory.FULL, OntologyFactory.NAMED );
+	    }
+	    classinst2 = new Set[nbclass2];
+	    for( Object cl2 : ontology2.getClasses() ) {
+		classinst2[ classlist2.get( cl2 ).intValue() ] = ontology2.getInstances( cl2, OntologyFactory.LOCAL, OntologyFactory.FULL, OntologyFactory.NAMED );
+	    }
+	} catch (OntowrapException owex) {
+	    owex.printStackTrace();
+	} catch (AlignmentException alex) {
+	    alex.printStackTrace();
+	}
+
+    }
+
+    public void compute( Properties params ) {
+	// First compute the distance on instances
+	computeInstanceDistance( params );
+	// Then compute class distances wrt parameters
+	computeClassDistance( params );
+    }
+
+    /**
+     * This is the empty method of this abstract class
+     * it must compute the instance distance
+     * and fill the adequate indmatrix with these distances.
+     */
+    public abstract void computeInstanceDistance( Properties params );
+
+    public void computeClassDistance( Properties params ) {
+	String cmeasure = params.getProperty( "cmeasure" );
+	if ( cmeasure != null && !cmeasure.equals( "singlel" ) ) {
+	    if ( cmeasure.equals( "fulll" ) ) {
+		computeFullLinkage();
+	    } else if ( cmeasure.equals( "averagel" ) ) {
+		computeAverageLinkage();
+	    } else if ( cmeasure.equals( "hausdorff" ) ) {
+		computeHausdorffDistance();
+	    }
+	} else {
+	    computeSingleLinkage();
+	}
+    }
+	
+    private void computeSingleLinkage() {
+	for ( int i=0; i < nbclass1; i++ ) {
+	    for ( int j=0; j < nbclass2; j++ ) {
+		double min = 1.;
+		for ( Object in1 : classinst1[i] ) {
+		    for ( Object in2 : classinst2[j] ) {
+			double val = indmatrix[indlist1.get( in1 ).intValue()][indlist2.get( in2 ).intValue()];
+			if ( val < min ) { min = val; }
+		    }
+		}
+		clmatrix[i][j] = min;
+	    }
+	}
+    }
+
+    private void computeFullLinkage() {
+	for ( int i=0; i < nbclass1; i++ ) {
+	    for ( int j=0; j < nbclass2; j++ ) {
+		double max = 0.;
+		for ( Object in1 : classinst1[i] ) {
+		    for ( Object in2 : classinst2[j] ) {
+			double val = indmatrix[indlist1.get( in1 ).intValue()][indlist2.get( in2 ).intValue()];
+			if ( val > max ) { max = val; }
+		    }
+		}
+		clmatrix[i][j] = max;
+	    }
+	}
+    }
+    private void computeAverageLinkage() {
+	for ( int i=0; i < nbclass1; i++ ) {
+	    for ( int j=0; j < nbclass2; j++ ) {
+		int nbval = 0;
+		double dist = 0.;
+		for ( Object in1 : classinst1[i] ) {
+		    for ( Object in2 : classinst2[j] ) {
+			nbval++;
+			dist += indmatrix[indlist1.get( in1 ).intValue()][indlist2.get( in2 ).intValue()];
+		    }
+		}
+		if ( nbval == 0 ) clmatrix[i][j] = 1.0;
+		else clmatrix[i][j] = dist/(double)nbval;
+	    }
+	}
+    }
+
+    private void computeHausdorffDistance() {
+	for ( int i=0; i < nbclass1; i++ ) {
+	    for ( int j=0; j < nbclass2; j++ ) {
+		if ( classinst1[i].size() == 0 && classinst2[j].size() == 0 ) clmatrix[i][j] = 1.;
+		double max = 0.;
+		for ( Object in1 : classinst1[i] ) {
+		    double min = 1.;
+		    for ( Object in2 : classinst2[j] ) {
+			double val = indmatrix[indlist1.get( in1 ).intValue()][indlist2.get( in2 ).intValue()];
+			if ( val < min ) min = val;
+		    }
+		    if ( min > max ) max = min;
+		}
+		for ( Object in2 : classinst2[j] ) {
+		    double min = 1.;
+		    for ( Object in1 : classinst1[i] ) {
+			double val = indmatrix[indlist1.get( in1 ).intValue()][indlist2.get( in2 ).intValue()];
+			if ( val < min ) min = val;
+		    }
+		    if ( min > max ) max = min;
+		}
+		clmatrix[i][j] = max;
+	    }
+	}
+    }
+
+    // These are useless because "compute" is overridden
+    public double measure( Object cl1, Object cl2 ) throws Exception {
+	return 0.;
+    }
+    public double classMeasure( Object cl1, Object cl2 ) throws Exception {
+	return 0.;
+    }
+    public double propertyMeasure( Object pr1, Object pr2 ) throws Exception {
+	return 0.;
+    }
+    public double individualMeasure( Object id1, Object id2 ) throws Exception {
+	//if ( debug > 4 ) System.err.println( "ID:"+id1+" -- "+id2);
+	// compute edit distance between both norms
+	//norm1[indlist1.get(ob1).intValue()], norm2[indlist2.get(ob2).intValue()]
+	return 0.;
+    }
+
+}
+