From a82815eb0521c12ba25c8018a19d0e44a3c1ab12 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Euzenat?= <Jerome.Euzenat@inria.fr>
Date: Thu, 15 Sep 2011 20:29:40 +0000
Subject: [PATCH] - Implemented extractss for ** alignments in
 DistanceAlignment (impl) - Changed default type of StringDistAlignment to
 "?*" for preserving the previous behaviour (impl) - Suppressed the guard for
 applying the Hungarian algorithm to equisimilarity situation (impl) - Fixed a
 bug on DistanceAlignment 1:1 extraction when the second ontology is larger
 than the first one (impl) - Added corresponding test

---
 html/relnotes.html                            |  14 +-
 .../exmo/align/impl/DistanceAlignment.java    | 246 +++++++++++-------
 .../impl/method/StringDistAlignment.java      |  13 +-
 test/src/MatcherTest.java                     | 130 ++++++++-
 4 files changed, 306 insertions(+), 97 deletions(-)

diff --git a/html/relnotes.html b/html/relnotes.html
index 57665a9c..8f9c27c0 100644
--- a/html/relnotes.html
+++ b/html/relnotes.html
@@ -56,12 +56,24 @@ The development of 4 versions continues.
 <li>Add more tests</li>
 </ul></p>
 
+<!-- NOTE FOR VERSION 5
+The default type of StringDistAlignment should be reverted to "**"
+with a warning: 
+-->
+
 <h2>Current SVN trunk version</h2>
 
-<!--h2>Version 4.3 (): xx/xx/xxxx - Zimt</h2-->
+<!--h2>Version 4.3 (): xx/xx/2011 - Zimt</h2-->
 <p><ul compact="1">
 <li>Full reengineering of the test generator (gen)</li>
+<li>Implemented <tt>extractss</tt> for ** alignments in <tt>DistanceAlignment</tt> (impl)</li>
+<li>Changed default type of <tt>StringDistAlignment</tt> to "?*" for
+  preserving the previous behaviour (impl)</li>
 <li>Added level lines in the triangle display of <tt>GroupEval</tt> (util)</li>
+<li>Suppressed the guard for applying the Hungarian algorithm to
+  equisimilarity situations (impl)</li>
+<li>Fixed a bug on <tt>DistanceAlignment</tt> 1:1 extraction when the
+  second ontology is larger than the first one (impl)</li>
 </ul></p>
 
 <h2>Version 4.2 (1618): 31/05/2011 - Tring</h2>
diff --git a/src/fr/inrialpes/exmo/align/impl/DistanceAlignment.java b/src/fr/inrialpes/exmo/align/impl/DistanceAlignment.java
index 99864d18..76385ec7 100644
--- a/src/fr/inrialpes/exmo/align/impl/DistanceAlignment.java
+++ b/src/fr/inrialpes/exmo/align/impl/DistanceAlignment.java
@@ -1,7 +1,7 @@
 /*
  * $Id$
  *
- * Copyright (C) INRIA, 2003-2010
+ * Copyright (C) INRIA, 2003-2011
  *
  * 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
@@ -138,16 +138,17 @@ public abstract class DistanceAlignment extends ObjectAlignment implements Align
 	if ( type.equals("?*") || type.equals("1*") || type.equals("?+") || type.equals("1+") ) return extractqs( threshold, params );
 	else if ( type.equals("??") || type.equals("1?") || type.equals("?1") || type.equals("11") ) return extractqq( threshold, params );
 	else if ( type.equals("*?") || type.equals("+?") || type.equals("*1") || type.equals("+1") ) return extractqs( threshold, params );
-	else if ( type.equals("**") || type.equals("+*") || type.equals("*+") || type.equals("++") ) return extractqs( threshold, params );
+	else if ( type.equals("**") || type.equals("+*") || type.equals("*+") || type.equals("++") ) return extractss( threshold, params );
 	// The else should be an error message
 	else throw new AlignmentException("Unknown alignment type: "+type);
     }
 
-    // JE: It is now certainly possible to virtualise extraction has it has
+    // JE: It is now certainly possible to virtualise extraction as it has
     // been done for printing matrix in MatrixMeasure (todo)
 
     /**
      * Extract the alignment of a ?* type
+     * Non symmetric: for each entity of onto1, take the highest if superior to threshold
      * Complexity: O(n^2)
      */
     @SuppressWarnings("unchecked") //ConcatenatedIterator
@@ -169,7 +170,7 @@ public abstract class DistanceAlignment extends ObjectAlignment implements Align
 				       ontology2().getDataProperties().iterator());
 	      for ( Object current : pit2 ){
 		  if ( sim.getSimilarity() ) val = sim.getPropertySimilarity(prop1,current);
-		  else val =  1 - sim.getPropertySimilarity(prop1,current);
+		  else val =  1. - sim.getPropertySimilarity(prop1,current);
 		  if ( val > max) {
 		      found = true; max = val; prop2 = current;
 		  }
@@ -182,7 +183,7 @@ public abstract class DistanceAlignment extends ObjectAlignment implements Align
 	      Object class2 = null;
 	      for ( Object current : ontology2().getClasses() ) {
 		  if ( sim.getSimilarity() ) val = sim.getClassSimilarity(class1,current);
-		  else val = 1 - sim.getClassSimilarity(class1,current);
+		  else val = 1. - sim.getClassSimilarity(class1,current);
 		  if (val > max) {
 		      found = true; max = val; class2 = current;
 		  }
@@ -213,10 +214,64 @@ public abstract class DistanceAlignment extends ObjectAlignment implements Align
       return((Alignment)this);
     }
 
+    /**
+     * Extract the alignment of a ** type
+     * Symmetric: return all elements above threshold
+     * Complexity: O(n^2)
+     */
+    @SuppressWarnings("unchecked") //ConcatenatedIterator
+    public Alignment extractss( double threshold, Properties params) {
+	double val = 0.;
+	try {
+	    // Extract for properties
+	    ConcatenatedIterator pit1 = new 
+		ConcatenatedIterator(ontology1().getObjectProperties().iterator(),
+				     ontology1().getDataProperties().iterator());
+	    for( Object prop1 : pit1 ){
+		ConcatenatedIterator pit2 = new 
+		    ConcatenatedIterator(ontology2().getObjectProperties().iterator(),
+					 ontology2().getDataProperties().iterator());
+		for ( Object prop2 : pit2 ){
+		    if ( sim.getSimilarity() ) val = sim.getPropertySimilarity(prop1,prop2);
+		    else val =  1. - sim.getPropertySimilarity(prop1,prop2);
+		    if ( val > threshold ) addAlignCell(prop1,prop2, "=", val);
+		}
+	    }
+	    // Extract for classes
+	    for ( Object class1 : ontology1().getClasses() ) {
+		for ( Object class2 : ontology2().getClasses() ) {
+		    if ( sim.getSimilarity() ) val = sim.getClassSimilarity(class1,class2);
+		    else val = 1. - sim.getClassSimilarity(class1,class2);
+		    if (val > threshold ) addAlignCell(class1, class2, "=", val);
+		}
+	    }
+	    // Extract for individuals
+	    if (  params.getProperty("noinst") == null ){
+		for ( Object ind1 : ontology1().getIndividuals() ) {
+		    if ( ontology1().getEntityURI( ind1 ) != null ) {
+			for ( Object ind2 : ontology2().getIndividuals() ) {
+			    if ( ontology2().getEntityURI( ind2 ) != null ) {
+				if ( sim.getSimilarity() ) val = sim.getIndividualSimilarity( ind1, ind2 );
+				else val = 1 - sim.getIndividualSimilarity( ind1, ind2 );
+				if ( val > threshold ) addAlignCell(ind1,ind2, "=", val);
+			    }
+			}
+		    }
+		}
+	    }
+	} catch (OntowrapException owex) { owex.printStackTrace(); //}
+	} catch (AlignmentException alex) { alex.printStackTrace(); }
+	return((Alignment)this);
+    }
+
     /**
      * Extract the alignment of a ?? type
      * 
-     * exact algorithm using the Hungarian method
+     * exact algorithm using the Hungarian method.
+     * This algorithm contains several guards to prevent the HungarianAlgorithm to
+     * raise problems:
+     * - It invert column and rows when nbrows > nbcol (Hungarian loops)
+     * - It prevents to generate alignments when one category has no elements.
      */
     @SuppressWarnings("unchecked") //ConcatenatedIterator
     public Alignment extractqq( double threshold, Properties params) {
@@ -227,29 +282,26 @@ public abstract class DistanceAlignment extends ObjectAlignment implements Align
 	    // Create a matrix
 	    int nbclasses1 = ontology1().nbClasses();
 	    int nbclasses2 = ontology2().nbClasses();
-	    double[][] matrix = new double[nbclasses1][nbclasses2];
-	    Object[] class1 = new Object[nbclasses1];
-	    Object[] class2 = new Object[nbclasses2];
-	    int i = 0;
-	    for ( Object ob : ontology1().getClasses() ) {
-		class1[i++] = ob;
-	    }
-	    int j = 0;
-	    for ( Object ob : ontology2().getClasses() ) {
-		class2[j++] = ob;
-	    }
-	    // ival indicates if all cells have the same value, or different (-1)
-	    double ival = sim.getClassSimilarity(class1[0],class2[0]);
-	    for( i = 0; i < nbclasses1; i++ ){
-		for( j = 0; j < nbclasses2; j++ ){
-		    if ( ival != -1. && ival != sim.getClassSimilarity(class1[i],class2[j] ) ) ival = -1.;
-		    if ( sim.getSimilarity() ) matrix[i][j] = sim.getClassSimilarity(class1[i],class2[j]);
-		    else matrix[i][j] = 1 - sim.getClassSimilarity(class1[i],class2[j]);
+	    if ( nbclasses1 != 0 && nbclasses2 != 0 ) {
+		double[][] matrix = new double[nbclasses1][nbclasses2];
+		Object[] class1 = new Object[nbclasses1];
+		Object[] class2 = new Object[nbclasses2];
+		int i = 0;
+		for ( Object ob : ontology1().getClasses() ) {
+		    class1[i++] = ob;
 		}
-	    }
-	    // Pass it to the algorithm
-	    if ( ival == -1. ) { // if values are the same, return an empty alignment
-		int[][] result = HungarianAlgorithm.hgAlgorithm( matrix, "max" );
+		int j = 0;
+		for ( Object ob : ontology2().getClasses() ) {
+		    class2[j++] = ob;
+		}
+		for( i = 0; i < nbclasses1; i++ ){
+		    for( j = 0; j < nbclasses2; j++ ){
+			if ( sim.getSimilarity() ) matrix[i][j] = sim.getClassSimilarity(class1[i],class2[j]);
+			else matrix[i][j] = 1. - sim.getClassSimilarity(class1[i],class2[j]);
+		    }
+		}
+		// Pass it to the algorithm
+		int[][] result = callHungarianMethod( matrix, nbclasses1, nbclasses2 );
 		// Extract the result
 		for( i=0; i < result.length ; i++ ){
 		    // The matrix has been destroyed
@@ -264,56 +316,53 @@ public abstract class DistanceAlignment extends ObjectAlignment implements Align
 		    }
 		}
 	    }
-	} catch (AlignmentException alex) { alex.printStackTrace(); }
-	catch (OntowrapException owex) { owex.printStackTrace(); }
+	} catch ( AlignmentException alex) { alex.printStackTrace(); }
+	catch ( OntowrapException owex) { owex.printStackTrace(); }
 	// For properties
 	try{
 	    int nbprop1 = ontology1().nbProperties();
 	    int nbprop2 = ontology2().nbProperties();
-	    double[][] matrix = new double[nbprop1][nbprop2];
-	    Object[] prop1 = new Object[nbprop1];
-	    Object[] prop2 = new Object[nbprop2];
-	    int i = 0;
-	    ConcatenatedIterator pit1 = new 
-		ConcatenatedIterator(ontology1().getObjectProperties().iterator(),
-				     ontology1().getDataProperties().iterator());
-	    for ( Object ob: pit1 ) prop1[i++] = ob;
-	    int j = 0;
-	    ConcatenatedIterator pit2 = new 
-		ConcatenatedIterator(ontology2().getObjectProperties().iterator(),
-				     ontology2().getDataProperties().iterator());
-	    for ( Object ob: pit2 ) prop2[j++] = ob;
-	    double ival = sim.getPropertySimilarity(prop1[0],prop2[0]);
-	    for( i = 0; i < nbprop1; i++ ){
-		for( j = 0; j < nbprop2; j++ ){
-		    if ( ival != -1. && ival != sim.getPropertySimilarity(prop1[i],prop2[j] ) ) ival = -1.;
-		    if ( sim.getSimilarity() ) matrix[i][j] = sim.getPropertySimilarity(prop1[i],prop2[j]);
-		    else 
-		    matrix[i][j] = 1 - sim.getPropertySimilarity(prop1[i],prop2[j]);
+	    if ( nbprop1 != 0 && nbprop2 != 0 ) {
+		double[][] matrix = new double[nbprop1][nbprop2];
+		Object[] prop1 = new Object[nbprop1];
+		Object[] prop2 = new Object[nbprop2];
+		int i = 0;
+		ConcatenatedIterator pit1 = new 
+		    ConcatenatedIterator(ontology1().getObjectProperties().iterator(),
+					 ontology1().getDataProperties().iterator());
+		for ( Object ob: pit1 ) prop1[i++] = ob;
+		int j = 0;
+		ConcatenatedIterator pit2 = new 
+		    ConcatenatedIterator(ontology2().getObjectProperties().iterator(),
+					 ontology2().getDataProperties().iterator());
+		for ( Object ob: pit2 ) prop2[j++] = ob;
+		for( i = 0; i < nbprop1; i++ ){
+		    for( j = 0; j < nbprop2; j++ ){
+			if ( sim.getSimilarity() ) matrix[i][j] = sim.getPropertySimilarity(prop1[i],prop2[j]);
+			else matrix[i][j] = 1. - sim.getPropertySimilarity(prop1[i],prop2[j]);
+		    }
 		}
-	    }
-	    // Pass it to the algorithm
-	if ( ival == -1. ) {
-	    int[][] result = HungarianAlgorithm.hgAlgorithm( matrix, "max" );
-	    // Extract the result
-	    for( i=0; i < result.length ; i++ ){
-		// The matrix has been destroyed
-		double val;
-		if ( sim.getSimilarity() ) val = sim.getPropertySimilarity(prop1[result[i][0]],prop2[result[i][1]]);
-		else val = 1 - sim.getPropertySimilarity(prop1[result[i][0]],prop2[result[i][1]]);
-		// JE: here using strict-> is a very good idea.
-		// it means that alignments with 0. similarity
-		// will be excluded from the best match. 
-		if( val > threshold ){
-		    addCell( new ObjectCell( (String)null, prop1[result[i][0]], prop2[result[i][1]], BasicRelation.createRelation("="), val ) );
+		// Pass it to the algorithm
+		int[][] result = callHungarianMethod( matrix, nbprop1, nbprop2 );
+		// Extract the result
+		for( i=0; i < result.length ; i++ ){
+		    // The matrix has been destroyed
+		    double val;
+		    if ( sim.getSimilarity() ) val = sim.getPropertySimilarity(prop1[result[i][0]],prop2[result[i][1]]);
+		    else val = 1 - sim.getPropertySimilarity(prop1[result[i][0]],prop2[result[i][1]]);
+		    // JE: here using strict-> is a very good idea.
+		    // it means that alignments with 0. similarity
+		    // will be excluded from the best match. 
+		    if( val > threshold ){
+			addCell( new ObjectCell( (String)null, prop1[result[i][0]], prop2[result[i][1]], BasicRelation.createRelation("="), val ) );
+		    }
 		}
 	    }
-	}
 	} catch (AlignmentException alex) { alex.printStackTrace(); }
 	catch (OntowrapException owex) { owex.printStackTrace(); }
 	// For individuals
 	if (  params.getProperty("noinst") == null ){
-	    try{
+	    try {
 		// Create individual lists
 		Object[] ind1 = new Object[ontology1().nbIndividuals()];
 		Object[] ind2 = new Object[ontology2().nbIndividuals()];
@@ -331,40 +380,53 @@ public abstract class DistanceAlignment extends ObjectAlignment implements Align
 			ind1[nbind1++] = ob;
 		    }
 		}
-		double[][] matrix = new double[nbind1][nbind2];
-		int i, j;
-	    double ival = sim.getIndividualSimilarity(ind1[0],ind2[0]);
-		for( i=0; i < nbind1; i++ ){
-		    for( j=0; j < nbind2; j++ ){
-			if ( ival != -1. && ival != sim.getIndividualSimilarity(ind1[i],ind2[j] ) ) ival = -1.;
-			if ( sim.getSimilarity() ) matrix[i][j] = sim.getIndividualSimilarity(ind1[i],ind2[j]);
-			else 
-			matrix[i][j] = 1 - sim.getIndividualSimilarity(ind1[i],ind2[j]);
+		if ( nbind1 != 0 && nbind2 != 0 ) {
+		    double[][] matrix = new double[nbind1][nbind2];
+		    int i, j;
+		    for( i=0; i < nbind1; i++ ){
+			for( j=0; j < nbind2; j++ ){
+			    if ( sim.getSimilarity() ) matrix[i][j] = sim.getIndividualSimilarity(ind1[i],ind2[j]);
+			    else matrix[i][j] = 1 - sim.getIndividualSimilarity(ind1[i],ind2[j]);
+			}
 		    }
-		}
-		// Pass it to the algorithm
-	if ( ival == -1. ) {
-		int[][] result = HungarianAlgorithm.hgAlgorithm( matrix, "max" );
-		// Extract the result
-		for( i=0; i < result.length ; i++ ){
-		    // The matrix has been destroyed
-		    double val;
-		    if ( sim.getSimilarity() ) val = sim.getIndividualSimilarity(ind1[result[i][0]],ind2[result[i][1]]);
-		    else val = 1 - sim.getIndividualSimilarity(ind1[result[i][0]],ind2[result[i][1]]);
-		    // JE: here using strict-> is a very good idea.
-		    // it means that alignments with 0. similarity
-		    // will be excluded from the best match. 
-		    if( val > threshold ){
-			addCell( new ObjectCell( (String)null, ind1[result[i][0]], ind2[result[i][1]], BasicRelation.createRelation("="), val ) );
+		    // Pass it to the algorithm
+		    int[][] result = callHungarianMethod( matrix, nbind1, nbind2 );
+		    // Extract the result
+		    for( i=0; i < result.length ; i++ ){
+			// The matrix has been destroyed
+			double val;
+			if ( sim.getSimilarity() ) val = sim.getIndividualSimilarity(ind1[result[i][0]],ind2[result[i][1]]);
+			else val = 1 - sim.getIndividualSimilarity(ind1[result[i][0]],ind2[result[i][1]]);
+			// JE: here using strict-> is a very good idea.
+			// it means that alignments with 0. similarity
+			// will be excluded from the best match. 
+			if( val > threshold ){
+			    addCell( new ObjectCell( (String)null, ind1[result[i][0]], ind2[result[i][1]], BasicRelation.createRelation("="), val ) );
+			}
 		    }
 		}
-	}
 	    } catch (AlignmentException alex) { alex.printStackTrace(); //}
 	    } catch (OntowrapException owex) { owex.printStackTrace(); }
 	}
 	return((Alignment)this);
     }
 
+    public int[][] callHungarianMethod( double[][] matrix, int i, int j ) {
+	boolean transposed = false;
+	if ( i > j ) { // transposed aray (because rows>columns).
+	    matrix = HungarianAlgorithm.transpose(matrix);
+	    transposed = true;
+	}
+	int[][] result = HungarianAlgorithm.hgAlgorithm( matrix, "max" );
+	if ( transposed ) {
+	    for( int k=0; k < result.length ; k++ ) { 
+		int val = result[k][0]; result[k][0] = result[k][1]; result[k][1] = val; 
+	    }
+	    
+	}
+	return result;
+    }
+
     /**
      * Greedy algorithm:
      * 1) dump the part of the matrix distance above threshold in a sorted set
diff --git a/src/fr/inrialpes/exmo/align/impl/method/StringDistAlignment.java b/src/fr/inrialpes/exmo/align/impl/method/StringDistAlignment.java
index e9ad98c8..39dc7813 100644
--- a/src/fr/inrialpes/exmo/align/impl/method/StringDistAlignment.java
+++ b/src/fr/inrialpes/exmo/align/impl/method/StringDistAlignment.java
@@ -1,7 +1,7 @@
 /*
  * $Id$
  *
- * Copyright (C) INRIA, 2003-2010
+ * Copyright (C) INRIA, 2003-2011
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -80,10 +80,17 @@ public class StringDistAlignment extends DistanceAlignment implements AlignmentP
 	}
     }
 
-    /** Creation **/
+    /**
+     * Creation
+     * (4.3) For compatibility reason with previous versions, the type is set to
+     * "?*" so that the behaviour is the same.
+     * In future version (5.0), this should be reverted to "**",
+     * so the extractors will behave differently
+     **/
     public StringDistAlignment() {
 	setSimilarity( new StringDistMatrixMeasure() );
-	setType("**");
+	setType("?*");
+	//setType("11");
     }
 
     /* Processing */
diff --git a/test/src/MatcherTest.java b/test/src/MatcherTest.java
index 4eefd406..f38f2dac 100644
--- a/test/src/MatcherTest.java
+++ b/test/src/MatcherTest.java
@@ -1,7 +1,7 @@
 /*
  * $Id$
  *
- * Copyright (C) INRIA, 2008-2010
+ * Copyright (C) INRIA, 2008-2011
  *
  * 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
@@ -34,9 +34,11 @@ import org.semanticweb.owl.align.AlignmentException;
 import org.semanticweb.owl.align.AlignmentProcess;
 import org.semanticweb.owl.align.Alignment;
 import org.semanticweb.owl.align.Evaluator;
+import org.semanticweb.owl.align.Cell;
 
 import fr.inrialpes.exmo.align.impl.renderer.RDFRendererVisitor;
 import fr.inrialpes.exmo.align.impl.method.StringDistAlignment;
+import fr.inrialpes.exmo.align.impl.MatrixMeasure;
 import fr.inrialpes.exmo.ontosim.string.StringDistances;
 import fr.inrialpes.exmo.align.impl.eval.PRecEvaluator;
 import fr.inrialpes.exmo.align.impl.URIAlignment;
@@ -117,4 +119,130 @@ $ java -jar lib/Procalign.jar file://$CWD/examples/rdf/edu.umbc.ebiquity.publica
 	alignment.init( new URI("file:examples/rdf/edu.umbc.ebiquity.publication.owl"), new URI("file:examples/rdf/edu.mit.visus.bibtex.owl"));
 	alignment.align( (Alignment)null, params );
     }
+
+    /* This tests an errors in extraction methods (Hungarian method) */
+    @Test(groups = { "full", "impl", "raw" })
+    public void hungarianExtractionTest() throws Exception {
+	StringDistAlignment dal = new StringDistAlignment();
+	dal.init( new URI("file:examples/rdf/edu.umbc.ebiquity.publication.owl"),  new URI("file:examples/rdf/edu.mit.visus.bibtex.owl") );
+	assertEquals( dal.nbCells(), 0 );
+	// Extract with nothing
+	Properties params = new Properties();
+	params.setProperty( "noinst", "1" );
+	dal.align( (Alignment)null, params ); // This initialises the matrix
+	assertEquals( dal.nbCells(), 10 );
+	// ****CLASSICAL EXTRACTIONS****
+ 	// Test ** extraction
+	for ( Cell c : dal ) { dal.removeAlignCell( c ); }
+	dal.extractqs( 0., params );
+	assertEquals( dal.nbCells(), 10 );
+	// Test 11 extraction
+	for ( Cell c : dal ) { dal.removeAlignCell( c ); }
+	dal.extractqq( 0., params );
+	assertEquals( dal.nbCells(), 10 );
+	for ( Cell c : dal ) { dal.removeAlignCell( c ); }
+	dal.extractqqgreedy( 0., params );
+	assertEquals( dal.nbCells(), 10 );
+	// ****ZERO'ED ALIGNMENT****
+	// Do it with only one cell... (all 0. but 1)
+	MatrixMeasure mm = (MatrixMeasure)dal.getSimilarity();
+	for ( int i = mm.nbclass1-1; i >= 0; i-- ) {
+	    for ( int j = mm.nbclass2-1; j >= 0; j-- ) {
+		mm.clmatrix[i][j] = 1.; // this is a distance...
+	    }
+	}
+	// Useless
+	for ( int i = mm.nbprop1-1; i >= 0; i-- ) {
+	    for ( int j = mm.nbprop2-1; j >= 0; j-- ) {
+		mm.prmatrix[i][j] = 1.; // distance...
+	    }
+	}
+	//dal.printDistanceMatrix( params );
+ 	// Test ** extraction
+	for ( Cell c : dal ) { dal.removeAlignCell( c ); }
+	//printAlignment( dal );
+	dal.extractqs( 0., params );
+	assertEquals( dal.nbCells(), 0 );
+	for ( Cell c : dal ) { dal.removeAlignCell( c ); }
+	dal.extractqs( 1., params );
+	assertEquals( dal.nbCells(), 0 );
+	// Test 11 extraction
+	for ( Cell c : dal ) { dal.removeAlignCell( c ); }
+	dal.extractqq( 0., params );
+	assertEquals( dal.nbCells(), 0 );
+	for ( Cell c : dal ) { dal.removeAlignCell( c ); }
+	dal.extractqqgreedy( 0., params );
+	assertEquals( dal.nbCells(), 0 );
+	// ****ADDED ONE EXPECTED CORRESPONDENCE****
+	// Do it with only one cell... (all 0. but 1)
+	mm.clmatrix[5][5] = .5;
+ 	// Test ** extraction
+	for ( Cell c : dal ) { dal.removeAlignCell( c ); }
+	//printAlignment( dal );
+	dal.extractqs( 0., params );
+	assertEquals( dal.nbCells(), 1 );
+	// ********  TEST THIS *******
+	//for ( Cell c : dal ) { dal.removeAlignCell( c ); }
+	//dal.extractqs( .6, params );
+	//assertEquals( dal.nbCells(), 0 );
+	// Test 11 extraction
+	for ( Cell c : dal ) { dal.removeAlignCell( c ); }
+	dal.extractqq( 0., params );
+	assertEquals( dal.nbCells(), 1 );
+	for ( Cell c : dal ) { dal.removeAlignCell( c ); }
+	dal.extractqqgreedy( 0., params );
+	assertEquals( dal.nbCells(), 1 );
+	// ****ADDED ONE EXPECTED CORRESPONDENCE****
+	// Do it with only one cell... (all 0. but 1)
+	mm.clmatrix[5][8] = .5;
+	mm.clmatrix[8][8] = .5;
+	mm.clmatrix[8][5] = .5;
+ 	// Test ** extraction
+	for ( Cell c : dal ) { dal.removeAlignCell( c ); }
+	//printAlignment( dal );
+	dal.extractqs( 0., params );
+	assertEquals( dal.nbCells(), 2 );
+	// ********  TEST THIS *******
+	//for ( Cell c : dal ) { dal.removeAlignCell( c ); }
+	//dal.extractqs( .6, params );
+	//assertEquals( dal.nbCells(), 0 );
+	// Test 11 extraction
+	for ( Cell c : dal ) { dal.removeAlignCell( c ); }
+	dal.extractqq( 0., params );
+	assertEquals( dal.nbCells(), 2 );
+	for ( Cell c : dal ) { dal.removeAlignCell( c ); }
+	dal.extractqqgreedy( 0., params );
+	assertEquals( dal.nbCells(), 2 );
+    }
+
+    /* This identifies a very specific bug in the Hungarian algorithm when:
+     * class2 < class1
+     * a subset of class2 is matched with a subset of class1
+     * In a simple 0/1 alignment
+     */
+    @Test(groups = { "full", "impl", "raw" }, dependsOnMethods = { "hungarianExtractionTest" })
+    public void naughtyHungarianExtractionTest() throws Exception {
+	StringDistAlignment dal = new StringDistAlignment();
+	dal.init( new URI("file:examples/rdf/edu.mit.visus.bibtex.owl"), new URI("file:examples/rdf/edu.umbc.ebiquity.publication.owl"));
+	assertEquals( dal.nbCells(), 0 );
+	// Extract with nothing
+	Properties params = new Properties();
+	params.setProperty( "noinst", "1" );
+	dal.align( (Alignment)null, params ); // This initialises the matrix
+	assertEquals( dal.nbCells(), 10 );
+	// Test 11 extraction
+	for ( Cell c : dal ) { dal.removeAlignCell( c ); }
+	dal.extractqq( 0., params );
+	assertEquals( dal.nbCells(), 10 ); // **** java.lang.ArrayIndexOutOfBoundsException: 0
+    }
+
+
+    public void printAlignment( Alignment dal ) {
+	try {
+	for ( Cell c : dal ) {
+	    System.err.println( "< "+c.getObject1AsURI(dal).getFragment()+" "+c.getRelation()+" "+c.getObject1AsURI(dal).getFragment()+" / "+c.getStrength() );
+	}
+	} catch (Exception e) {}
+    }
+
 }
-- 
GitLab