Index: /cpp/frams/Makefile-SDK-files
===================================================================
--- /cpp/frams/Makefile-SDK-files	(revision 1043)
+++ /cpp/frams/Makefile-SDK-files	(revision 1044)
@@ -2,5 +2,5 @@
 
 # ALL_DIRS is later expanded by the shell, no spaces/newlines allowed, or it breaks
-ALL_DIRS={common,PrintFloat,frams,frams/canvas,frams/config,common/loggers,frams/genetics,frams/genetics/f0,frams/genetics/f1,frams/genetics/f2,frams/genetics/f3,frams/genetics/f4,frams/genetics/f5,frams/genetics/f6,frams/genetics/f7,frams/genetics/f8,frams/genetics/f9,frams/genetics/fn,frams/genetics/fF,frams/genetics/fT,frams/genetics/fB,frams/genetics/fH,frams/genetics/fL,frams/genetics/fS,frams/model,frams/neuro,frams/neuro/impl,frams/param,frams/test,frams/util,frams/vm/classes,common/virtfile,frams/_demos,frams/model/geometry,frams/_demos/geometry,frams/model/similarity,frams/model/similarity/hungarian,frams/model/similarity/SVD}
+ALL_DIRS={common,PrintFloat,frams,frams/canvas,frams/config,common/loggers,frams/genetics,frams/genetics/f0,frams/genetics/f1,frams/genetics/f2,frams/genetics/f3,frams/genetics/f4,frams/genetics/f5,frams/genetics/f6,frams/genetics/f7,frams/genetics/f8,frams/genetics/f9,frams/genetics/fn,frams/genetics/fF,frams/genetics/fT,frams/genetics/fB,frams/genetics/fH,frams/genetics/fL,frams/genetics/fS,frams/model,frams/neuro,frams/neuro/impl,frams/param,frams/test,frams/util,frams/vm/classes,common/virtfile,frams/_demos,frams/model/geometry,frams/_demos/geometry,frams/model/similarity,frams/model/similarity/hungarian,frams/model/similarity/SVD,frams/model/similarity/EMD}
 
 GEOMETRY_OBJS=frams/model/geometry/meshbuilder.o frams/model/geometry/modelgeometryinfo.o frams/model/geometry/geometryutils.o
@@ -37,5 +37,5 @@
 NEURO_OBJS=frams/neuro/neuroimpl.o frams/neuro/neurofactory.o frams/neuro/impl/neuroimpl-simple.o frams/neuro/impl/neuroimpl-channels.o frams/neuro/impl/neuroimpl-fuzzy.o frams/neuro/impl/neuroimpl-fuzzy-f0.o
 
-SIMILARITY_OBJS=frams/model/similarity/hungarian/hungarian.o frams/model/similarity/SVD/lapack.o frams/model/similarity/SVD/matrix_tools.o frams/model/similarity/simil_match.o frams/model/similarity/simil_model.o
+SIMILARITY_OBJS=frams/_demos/geometry/geometrytestutils.o frams/model/similarity/measure-greedy.o frams/model/similarity/measure-hungarian.o frams/model/similarity/measure-distribution.o frams/model/similarity/measure-mds-based.o frams/model/similarity/simil-measure.o frams/model/similarity/hungarian/hungarian.o frams/model/similarity/SVD/lapack.o frams/model/similarity/SVD/matrix_tools.o frams/model/similarity/simil-match.o
 
 NN_LAYOUT_OBJS=frams/canvas/nn_layout_model.o frams/canvas/nn_simple_layout.o frams/canvas/nn_smart_layout.o
@@ -96,9 +96,9 @@
 SIMIL_TEST_OBJS=frams/_demos/simil_test.o $(SIMILARITY_OBJS) frams/_demos/genotypeloader.o frams/_demos/genotypemini.o frams/param/multiparamload.o common/virtfile/stdiofile.o $(STDOUT_LOGGER_OBJS) $(SDK_OBJS) $(GENOCONV_AND_GENMAN_SDK_OBJS)
 
-SIMIL_UNITTESTS_OBJS=frams/_demos/simil_unittests.o frams/model/similarity/simil_match.o
+SIMIL_UNITTESTS_OBJS=frams/_demos/simil_unittests.o frams/model/similarity/simil-match.o
 
 PARAMTREE_STDIN_TEST_OBJS=frams/_demos/paramtree_stdin_test.o frams/_demos/paramtree_print.o $(STDOUT_LOGGER_OBJS) common/virtfile/stdiofile.o $(SDK_OBJS) frams/param/paramtree.o
 
-PARAMTREE_PARAMLIST_TEST_OBJS=$(sort frams/_demos/paramtree_paramlist_test.o frams/_demos/paramtree_print.o $(STDOUT_LOGGER_OBJS) common/virtfile/stdiofile.o $(SDK_OBJS) $(GENOCONV_AND_GENMAN_SDK_OBJS) frams/neuro/neuroimpl.o frams/neuro/neurofactory.o frams/neuro/impl/neuroimpl-simple.o frams/neuro/impl/neuroimpl-channels.o frams/neuro/impl/neuroimpl-fuzzy.o frams/neuro/impl/neuroimpl-fuzzy-f0.o $(GENOTYPE_LOADER_OBJS) $(GEOMETRY_OBJS) frams/model/geometry/modelgeoclass.o frams/model/modelobj.o frams/param/paramtree.o)
+PARAMTREE_PARAMLIST_TEST_OBJS=$(sort frams/_demos/paramtree_paramlist_test.o frams/_demos/paramtree_print.o $(STDOUT_LOGGER_OBJS) common/virtfile/stdiofile.o $(SDK_OBJS) $(GENOCONV_AND_GENMAN_SDK_OBJS) frams/neuro/neuroimpl.o frams/neuro/neurofactory.o frams/neuro/impl/neuroimpl-simple.o frams/neuro/impl/neuroimpl-channels.o frams/neuro/impl/neuroimpl-fuzzy.o frams/neuro/impl/neuroimpl-fuzzy-f0.o $(GENOTYPE_LOADER_OBJS) $(GEOMETRY_OBJS) $(SIMILARITY_OBJS) frams/model/geometry/modelgeoclass.o frams/model/modelobj.o frams/param/paramtree.o)
 
 MUTABLEPARAM_TEST_OBJS=frams/_demos/mutableparam_test.o $(STDOUT_LOGGER_OBJS) common/virtfile/stdiofile.o $(SDK_OBJS) frams/param/mutableparam.o frams/param/mutparamlist.o frams/param/paramtrans.o
Index: /cpp/frams/_demos/paramtree_paramlist_test.cpp
===================================================================
--- /cpp/frams/_demos/paramtree_paramlist_test.cpp	(revision 1043)
+++ /cpp/frams/_demos/paramtree_paramlist_test.cpp	(revision 1044)
@@ -11,4 +11,7 @@
 #include <frams/model/geometry/modelgeoclass.h>
 #include <frams/model/modelobj.h>
+#include <frams/model/similarity/measure-distribution.h>
+#include <frams/model/similarity/measure-greedy.h>
+#include <frams/model/similarity/measure-hungarian.h>
 #include "genotypeloader.h"
 #include "paramtree_print.h"
@@ -27,4 +30,7 @@
 	NeuroNetConfig nn_config(&neurofac);
 	ModelGeometry modelgeo;
+	SimilMeasureDistribution simil_measure_distr;
+	SimilMeasureGreedy simil_measure_greedy;
+	SimilMeasureHungarian simil_measure_hungarian;
 
 	MutableParamList combined;
@@ -39,4 +45,7 @@
 	combined += &nn_config.par;
 	combined += &modelgeo.par;
+	combined += &simil_measure_distr.localpar;
+	combined += &simil_measure_greedy.localpar;
+	combined += &simil_measure_hungarian.localpar;
 
 	ParamTree tree(&combined);
Index: /cpp/frams/_demos/simil_test.cpp
===================================================================
--- /cpp/frams/_demos/simil_test.cpp	(revision 1043)
+++ /cpp/frams/_demos/simil_test.cpp	(revision 1044)
@@ -5,11 +5,37 @@
 
 #include <vector>
+#include <string>
 #include "common/loggers/loggertostdout.h"
 #include "frams/_demos/genotypeloader.h"
 #include "frams/genetics/preconfigured.h"
 #include "common/virtfile/stdiofile.h"
-#include "frams/model/similarity/simil_model.h"
-
-
+#include "frams/model/similarity/measure-distribution.h"
+#include "frams/model/similarity/measure-greedy.h"
+#include "frams/model/similarity/measure-hungarian.h"
+
+using namespace std;
+
+int add_double_param(std::vector<string> *args, int pos, std::vector<double> *params, std::vector<string> *params_names)
+{
+    for (unsigned int i = 0; i < params_names->size(); i++)
+    {
+        try
+        {
+            params->push_back(std::stod(args->at(pos)));
+            pos++;
+        }
+        catch (const std::invalid_argument&)
+        {
+            printf("%s should be a number\n", params_names->at(i).c_str());
+            return -1;
+        }
+        catch (const std::out_of_range&)
+        {
+            printf("%s should be inside double range\n", params_names->at(i).c_str());
+            return -1;
+        }
+    }
+    return 0;
+}
 
 /** Computes a matrix of distances between all genotypes in the specified
@@ -18,206 +44,181 @@
 int main(int argc, char *argv[])
 {
-	LoggerToStdout messages_to_stdout(LoggerBase::Enable);
-	int iCurrParam = 0; // index of the currently processed parameter
-	char *szCurrParam = NULL;
-	ModelSimil M; // similarity computing object
-	bool bPrintNames = false; // specifies if names of genotypes are to be printed
-	int nResult = 0; // a temporary result
-
-	if (argc < 8)
-	{
-		printf("Too few parameters!\n");
-		printf("Command line: [-names] <genotypesFile> <measure> <w_dP> <w_dDEG> <w_dNEU> <w_dGEO> <fixZaxis?>\n\n");
-
-		printf("Parameters:\n");
-		printf("  <genotypesFile> name of a file with genotypes\n");
-		printf("  <measure> similarity measure\n");
-		printf("  <w_dP> weight of the difference in the number of parts\n");
-		printf("  <w_dDEG> weight of the difference in degrees of matched parts\n");
-		printf("  <w_dNEU> weight of the difference in neurons of matched parts\n");
-		printf("  <w_dGEO> weight of the distance of matched parts\n");
-		printf("  <fixZaxis?> should the 'z' (vertical) coordinate be fixed during the alignment? (0 or 1)\n\n");
-
-		printf("Switches:\n");
-		printf("  -names specifies that the number and names of genotypes are to be printed to output\n");
-		printf("  before the distance matrix; by default the number and names are not printed\n\n");
-
-		printf("Outputs a symmetric distance matrix in the format:\n");
-		printf("  <row_1> (columns in a row are separated by TABs)\n");
-		printf("  ...\n");
-		printf("  <row_n>\n");
-
-		return -1;
-	}
-
-	// prepare output parameters from .gen file
-	vector<Geno *> pvGenos;
-	vector<char *> pvNames;
-
-	// check if there is a switch
-	iCurrParam = 1;
-	szCurrParam = argv[iCurrParam];
-	if (strcmp(szCurrParam, "-names") == 0)
-	{
-		// switch "-names" was given; print names also
-		bPrintNames = true;
-		// pass to the next parameter
-		iCurrParam++;
-	}
-
-	// check the parameters
-	// get <genotypesFile> name from command line
-	char *szFileName = argv[iCurrParam];
-
-	// initially set measure components' weights to invalid values (negative)
-	for (int i = 0; i < M.GetNOFactors(); i++)
-	{
-		M.m_adFactors[i] = -1.0;
-	}
-
-	iCurrParam++;
-	szCurrParam = argv[iCurrParam];
-	int measure_type = -1;
-	nResult = sscanf(szCurrParam, "%d", &measure_type);
-	if (nResult != 1)
-	{
-		printf("Measure type should be a number!\n");
-		return -1;
-	}
-
-	if (measure_type != 0 && measure_type != 1)
-	{
-		printf("Measure type should be 0 (flexible criteria order and optimal matching) or 1 (vertex degree order and greedy matching)!\n");
-		return -1;
-	}
-
-	M.matching_method = measure_type;
-
-	const char *params[] = { "<w_dP>", "<w_dDEG>", "<w_dNEU>", "<w_dGEO>" };
-	for (int i = 0; i < M.GetNOFactors(); i++)
-	{
-		iCurrParam++;
-		szCurrParam = argv[iCurrParam];
-		nResult = sscanf(szCurrParam, "%lf", &M.m_adFactors[i]);
-		if (nResult != 1)
-		{
-			// <w_dX> is not a number -- error
-			printf("%s", params[i]);
-			printf(" should be a number\n");
-			return -1;
-		}
-		else
-		{
-			// <w_dX> is a number; check if nonnegative
-			if (M.m_adFactors[i] < 0.0)
-			{
-				printf("%s", params[i]);
-				printf(" should be a nonnegative number\n");
-				return -1;
-			}
-		}
-	}
-
-	iCurrParam++;
-	szCurrParam = argv[iCurrParam];
-	nResult = sscanf(szCurrParam, "%d", &M.fixedZaxis);
-	if (nResult != 1)
-	{
-		// <isZFixed> is not a number -- error
-		printf("<isZFixed> should be a number\n");
-		return -1;
-	}
-	else if (M.fixedZaxis != 0 && M.fixedZaxis != 1)
-	{
-		printf("<isZFixed>=%d. <isZFixed> should be equal to 0 or 1\n", M.fixedZaxis);
-		return -1;
-	}
-
-	// read the input file
-	// prepare loading of genotypes from a .gen file
-	// create some basic genotype converters
-	PreconfiguredGenetics genetics;
-	StdioFileSystem_autoselect stdiofilesys;
-
-	long count = 0, totalsize = 0;
-	GenotypeMiniLoader loader(szFileName);
-	GenotypeMini *loaded;
-	while (loaded = loader.loadNextGenotype())
-	{
-		// while a valid genotype was loaded
-		count++;
-		totalsize += loaded->genotype.length();
-		// create a Geno object based on the MiniGenotype
-		Geno *pNextGenotype = new Geno(loaded->genotype);
-		if ((pNextGenotype != NULL) && (pNextGenotype->isValid()))
-		{
-			pvGenos.push_back(pNextGenotype);
-			char *szNewName = new char[loaded->name.length() + 1];
-			strcpy(szNewName, loaded->name.c_str());
-			pvNames.push_back(szNewName);
-		}
-		else
-		{
-			printf("Genotype %2li is not valid\n", count);
-			if (pNextGenotype != NULL) delete pNextGenotype;
-		}
-	}
-	if (loader.getStatus() == GenotypeMiniLoader::OnError)
-	{
-		printf("Error: %s", loader.getError().c_str());
-	}
-
-	double dSimilarity = 0.0;
-	double **aaSimil = NULL; // array of similarities
-
-	// create an empty array of similarities
-	aaSimil = new double*[pvGenos.size()];
-	for (unsigned int k = 0; k < pvGenos.size(); k++)
-	{
-		aaSimil[k] = new double[pvGenos.size()];
-		for (unsigned int l = 0; l < pvGenos.size(); l++)
-			aaSimil[k][l] = 0.0;
-	}
-
-	// compute and store similarities
-	for (unsigned int i = 0; i < pvGenos.size(); i++)
-	{
-		for (unsigned int j = 0; j < pvGenos.size(); j++)
-		{
-			dSimilarity = M.EvaluateDistance(pvGenos.operator[](i), pvGenos.operator[](j));
-			aaSimil[i][j] = dSimilarity;
-		}
-	}
-
-	if (bPrintNames)
-	{
-		// if the "-names" switch was given, print the number of genotypes and their names
-		printf("%li\n", pvGenos.size());
-		for (unsigned int iGen = 0; iGen < pvNames.size(); iGen++)
-		{
-			printf("%s\n", pvNames.at(iGen));
-		}
-	}
-
-	// print out the matrix of similarities
-	for (unsigned int i = 0; i < pvGenos.size(); i++)
-	{
-		for (unsigned int j = 0; j < pvGenos.size(); j++)
-		{
-			printf("%.2lf\t", aaSimil[i][j]);
-		}
-		printf("\n");
-	}
-
-	// delete vectors and arrays
-	for (unsigned int i = 0; i < pvGenos.size(); i++)
-	{
-		delete pvGenos.operator[](i);
-		delete[] pvNames.operator[](i);
-		delete[] aaSimil[i];
-	}
-
-	delete[] aaSimil;
-
-	return 0;
+    typedef double *pDouble;
+    LoggerToStdout messages_to_stdout(LoggerBase::Enable);
+    SimilMeasure *simil_measure = nullptr;
+    if (argc < 5)
+    {
+        printf("Too few parameters!\n");
+        printf("Command line: [-names] <genotypesFile> <measure (greedy/hungarian)> <w_dP> <w_dDEG> <w_dNEU> <w_dGEO> <fixZaxis?>\n\n");
+        printf("Command line: [-names] <genotypesFile> <measure (distribution)> <desc> <simil> <dens> <bins> <samp_num>\n\n");
+        printf("Parameters:\n");
+        printf("  <genotypesFile> name of a file with genotypes\n");
+        printf("  <measure> similarity measure name (greedy/hungarian/distribution)\n");
+        printf("\n");
+        printf("Parameters of greedy and hungarian measures:\n");
+        printf("  <w_dP> weight of the difference in the number of parts\n");
+        printf("  <w_dDEG> weight of the difference in degrees of matched parts\n");
+        printf("  <w_dNEU> weight of the difference in neurons of matched parts\n");
+        printf("  <w_dGEO> weight of the distance of matched parts\n");
+        printf("  <fixZaxis?> should the 'z' (vertical) coordinate be fixed during the alignment? (0 or 1)\n\n");
+        printf("Parameters of distribution measure:\n");
+        printf("  <dens> sampling density\n");
+        printf("  <bins> number of histogram bins\n");
+        printf("  <samp_num> number of samples taken\n\n");
+
+        printf("Switches:\n");
+        printf("  -names specifies that the number and names of genotypes are to be printed to output\n");
+        printf("  before the distance matrix; by default the number and names are not printed\n\n");
+
+        printf("Outputs a symmetric distance matrix in the format:\n");
+        printf("  <row_1> (columns in a row are separated by TABs)\n");
+        printf("  ...\n");
+        printf("  <row_n>\n");
+
+        return -1;
+    }
+
+    std::vector<string> args;
+    for (int i = 1; i < argc; i++)
+        args.push_back(std::string(argv[i]));
+
+    bool print_names = false;
+
+    int pos = 1;
+    if (args.at(0).compare("-names")==0)
+    {
+        print_names = true;
+        pos = 2;
+    }
+
+    string measure_name = args.at(pos);
+    pos++;
+    std::vector<double> params;
+
+    if (measure_name.compare("greedy")==0 || measure_name.compare("hungarian")==0)
+    {
+        std::vector<string> params_names{ "<w_dP>", "<w_dDEG>", "<w_dNEU>", "<w_dGEO>",  "<fixZaxis?>" };
+
+        if (add_double_param(&args, pos, &params, &params_names) == -1)
+            return -1;
+
+        if (measure_name.compare("greedy")==0)
+            simil_measure = new SimilMeasureGreedy();
+        else
+            simil_measure = new SimilMeasureHungarian();
+    }
+
+
+    else if (measure_name.compare("distribution")==0)
+    {
+        std::vector<string> params_names{ "<dens>", "<bins>", "<samp_num>" };
+
+        if (add_double_param(&args, pos, &params, &params_names)==-1)
+            return -1;
+
+        simil_measure = new SimilMeasureDistribution();
+    }
+
+    else
+    {
+        printf("Measure type should be greedy (flexible criteria order and optimal matching), hungarian (vertex degree order and greedy matching) or distribution!\n");
+        return -1;
+    }
+
+    simil_measure->setParams(params);
+
+    // read the input file
+    // prepare loading of genotypes from a .gen file
+    // create some basic genotype converters
+    PreconfiguredGenetics genetics;
+    StdioFileSystem_autoselect stdiofilesys;
+
+    // prepare output parameters from .gen file
+    vector<Geno *> pvGenos;
+    vector<char *> pvNames;
+
+    long count = 0, totalsize = 0;
+    GenotypeMiniLoader loader(args.at(0).c_str());
+    GenotypeMini *loaded;
+    while (loaded = loader.loadNextGenotype())
+    {
+        // while a valid genotype was loaded
+        count++;
+        totalsize += loaded->genotype.length();
+        // create a Geno object based on the MiniGenotype
+        Geno *pNextGenotype = new Geno(loaded->genotype);
+        if ((pNextGenotype != NULL) && (pNextGenotype->isValid()))
+        {
+            pvGenos.push_back(pNextGenotype);
+            char *szNewName = new char[loaded->name.length() + 1];
+            strcpy(szNewName, loaded->name.c_str());
+            pvNames.push_back(szNewName);
+        }
+        else
+        {
+            printf("Genotype %2li is not valid\n", count);
+            if (pNextGenotype != NULL) delete pNextGenotype;
+        }
+    }
+    if (loader.getStatus() == GenotypeMiniLoader::OnError)
+    {
+        printf("Error: %s", loader.getError().c_str());
+    }
+
+    double dSimilarity = 0.0;
+    double **aaSimil = NULL; // array of similarities
+
+    // create the empty array of similarities
+    aaSimil = new pDouble[pvGenos.size()];
+    for (unsigned int k = 0; k < pvGenos.size(); k++)
+    {
+        aaSimil[k] = new double[pvGenos.size()];
+        for (unsigned int l = 0; l < pvGenos.size(); l++)
+            aaSimil[k][l] = 0.0;
+    }
+
+
+
+    // compute and remember similarities
+    for (unsigned int i = 0; i < pvGenos.size(); i++)
+    {
+        for (unsigned int j = 0; j < pvGenos.size(); j++)
+        {
+            dSimilarity = simil_measure->evaluateDistance(pvGenos.operator[](i), pvGenos.operator[](j));
+            aaSimil[i][j] = dSimilarity;
+        }
+    }
+
+    if (print_names)
+    {
+        // if "-names" switch was given, print the number of genotypes and their names
+        printf("%li\n", pvGenos.size());
+        for (unsigned int iGen = 0; iGen < pvNames.size(); iGen++)
+        {
+            printf("%s\n", pvNames.at(iGen));
+        }
+    }
+
+    // print out the matrix of similarities
+    for (unsigned int i = 0; i < pvGenos.size(); i++)
+    {
+        for (unsigned int j = 0; j < pvGenos.size(); j++)
+        {
+            printf("%.2lf\t", aaSimil[i][j]);
+        }
+        printf("\n");
+    }
+
+    // delete vectors and arrays
+    for (unsigned int i = 0; i < pvGenos.size(); i++)
+    {
+        delete pvGenos.operator[](i);
+        delete[] pvNames.operator[](i);
+        delete[] aaSimil[i];
+    }
+
+    delete[] aaSimil;
+    delete simil_measure;
+
+    return 0;
 }
Index: /cpp/frams/_demos/simil_unittests.cpp
===================================================================
--- /cpp/frams/_demos/simil_unittests.cpp	(revision 1043)
+++ /cpp/frams/_demos/simil_unittests.cpp	(revision 1044)
@@ -3,5 +3,5 @@
 // See LICENSE.txt for details.
 
-#include "frams/model/similarity/simil_match.h"
+#include "frams/model/similarity/simil-match.h"
 
 /** Runs unit tests of classes used in computation of similarity.
@@ -42,10 +42,10 @@
         for (i = 0; i < nSize1; i++)
         {
-            assert(match1.IsMatched(j, i) == false);
+            assert(match1.isMatched(j, i) == false);
         }
     }
 
     // test if all are unmatched - new method
-    assert(match1.IsEmpty() == true);
+    assert(match1.isEmpty() == true);
 
     // check assymetric matching
@@ -55,14 +55,14 @@
     for (i = 0; i < nSize1; i++)
     {
-        assert(match2.IsMatched(0, i) == false);
+        assert(match2.isMatched(0, i) == false);
     }
     // check if all elements are unmatched yet in object 1
     for (i = 0; i < nSize2; i++)
     {
-        assert(match2.IsMatched(1, i) == false);
+        assert(match2.isMatched(1, i) == false);
     }
 
     // test if all are unmatched - new method
-    assert(match2.IsEmpty() == true);
+    assert(match2.isEmpty() == true);
 
     return 0;
@@ -89,6 +89,6 @@
 
             // check size of both objects
-            assert(pMatching->GetObjectSize(0) == i);
-            assert(pMatching->GetObjectSize(1) == j);
+            assert(pMatching->getObjectSize(0) == i);
+            assert(pMatching->getObjectSize(1) == j);
 
             // delete disused object
@@ -114,20 +114,20 @@
         SimilMatching Source(iSize, iSize);
         // check if it is empty
-        assert(Source.IsEmpty() == true);
+        assert(Source.isEmpty() == true);
         // check sizes of objects
-        assert(Source.GetObjectSize(0) == iSize);
-        assert(Source.GetObjectSize(1) == iSize);
+        assert(Source.getObjectSize(0) == iSize);
+        assert(Source.getObjectSize(1) == iSize);
         // create a copy of this matching
         SimilMatching Dest(Source);
         // check the copy:
         // - sizes of matched object
-        assert(Dest.GetObjectSize(0) == Source.GetObjectSize(0));
-        assert(Dest.GetObjectSize(1) == Source.GetObjectSize(1));
+        assert(Dest.getObjectSize(0) == Source.getObjectSize(0));
+        assert(Dest.getObjectSize(1) == Source.getObjectSize(1));
         // - the copy should be empty, too
-        assert(Dest.IsEmpty() == true);
+        assert(Dest.isEmpty() == true);
         // make it empty once again
-        Dest.Empty();
+        Dest.empty();
         // and check once more
-        assert(Dest.IsEmpty() == true);
+        assert(Dest.isEmpty() == true);
     }
 
@@ -136,23 +136,23 @@
         SimilMatching Source(iSize, iSize);
         // check if it is empty
-        assert(Source.IsEmpty() == true);
+        assert(Source.isEmpty() == true);
         // check sizes of objects
-        assert(Source.GetObjectSize(0) == iSize);
-        assert(Source.GetObjectSize(1) == iSize);
+        assert(Source.getObjectSize(0) == iSize);
+        assert(Source.getObjectSize(1) == iSize);
         // match objects (iObj, iObj)
         for (iObj = 0; iObj < iSize; iObj++)
         {
-            Source.Match(0, iObj, 1, iObj);
+            Source.match(0, iObj, 1, iObj);
         }
         // check if the matching is full
-        assert(Source.IsFull() == true);
+        assert(Source.isFull() == true);
         // now create a copy of the matching
         SimilMatching Dest(Source);
         // check the copy
         // - sizes of matched object
-        assert(Dest.GetObjectSize(0) == Source.GetObjectSize(0));
-        assert(Dest.GetObjectSize(1) == Source.GetObjectSize(1));
+        assert(Dest.getObjectSize(0) == Source.getObjectSize(0));
+        assert(Dest.getObjectSize(1) == Source.getObjectSize(1));
         // - the copy should be full, too
-        assert(Dest.IsFull() == true);
+        assert(Dest.isFull() == true);
         // - the copy should have exactly the same assignments in matching
         for (iObj = 0; iObj < iSize; iObj++)
@@ -160,14 +160,14 @@
             // all object should be matched!
             // check both directions: 0 -> 1
-            assert(Dest.IsMatched(0, iObj) == true);
-            assert(iObj == Dest.GetMatchedIndex(0, iObj));
+            assert(Dest.isMatched(0, iObj) == true);
+            assert(iObj == Dest.getMatchedIndex(0, iObj));
             // and: 1 -> 0
-            assert(Dest.IsMatched(1, iObj) == true);
-            assert(iObj == Dest.GetMatchedIndex(1, iObj));
+            assert(Dest.isMatched(1, iObj) == true);
+            assert(iObj == Dest.getMatchedIndex(1, iObj));
         }
         // make it empty
-        Dest.Empty();
+        Dest.empty();
         // and check once more
-        assert(Dest.IsEmpty() == true);
+        assert(Dest.isEmpty() == true);
     }
 
@@ -176,23 +176,23 @@
         SimilMatching Source(iSize, iSize);
         // check if it is empty
-        assert(Source.IsEmpty() == true);
+        assert(Source.isEmpty() == true);
         // check sizes of objects
-        assert(Source.GetObjectSize(0) == iSize);
-        assert(Source.GetObjectSize(1) == iSize);
+        assert(Source.getObjectSize(0) == iSize);
+        assert(Source.getObjectSize(1) == iSize);
         // match objects (iObj, N - iObj - 1)
         for (iObj = 0; iObj < iSize; iObj++)
         {
-            Source.Match(0, iObj, 1, iSize - iObj - 1);
+            Source.match(0, iObj, 1, iSize - iObj - 1);
         }
         // check if the matching is full
-        assert(Source.IsFull() == true);
+        assert(Source.isFull() == true);
         // now create a copy of the matching
         SimilMatching Dest(Source);
         // check the copy
         // - sizes of matched object
-        assert(Dest.GetObjectSize(0) == Source.GetObjectSize(0));
-        assert(Dest.GetObjectSize(1) == Source.GetObjectSize(1));
+        assert(Dest.getObjectSize(0) == Source.getObjectSize(0));
+        assert(Dest.getObjectSize(1) == Source.getObjectSize(1));
         // - the copy should be full, too
-        assert(Dest.IsFull() == true);
+        assert(Dest.isFull() == true);
         // - the copy should have exactly the same assignments in matching
         for (iObj = 0; iObj < iSize; iObj++)
@@ -200,14 +200,14 @@
             // all object should be matched!
             // check both directions: 0 -> 1
-            assert(Dest.IsMatched(0, iObj) == true);
-            assert((iSize - iObj - 1) == Dest.GetMatchedIndex(0, iObj));
+            assert(Dest.isMatched(0, iObj) == true);
+            assert((iSize - iObj - 1) == Dest.getMatchedIndex(0, iObj));
             // and: 1 -> 0
-            assert(Dest.IsMatched(1, iObj) == true);
-            assert((iSize - iObj - 1) == Dest.GetMatchedIndex(1, iObj));
+            assert(Dest.isMatched(1, iObj) == true);
+            assert((iSize - iObj - 1) == Dest.getMatchedIndex(1, iObj));
         }
         // make it empty
-        Dest.Empty();
+        Dest.empty();
         // and check once more
-        assert(Dest.IsEmpty() == true);
+        assert(Dest.isEmpty() == true);
     }
 
@@ -216,23 +216,23 @@
         SimilMatching Source(iSize, 2 * iSize);
         // check if it is empty
-        assert(Source.IsEmpty() == true);
+        assert(Source.isEmpty() == true);
         // check sizes of objects
-        assert(Source.GetObjectSize(0) == iSize);
-        assert(Source.GetObjectSize(1) == 2 * iSize);
+        assert(Source.getObjectSize(0) == iSize);
+        assert(Source.getObjectSize(1) == 2 * iSize);
         // match objects (iObj, 2 * iObj)
         for (iObj = 0; iObj < iSize; iObj++)
         {
-            Source.Match(0, iObj, 1, 2 * iObj);
+            Source.match(0, iObj, 1, 2 * iObj);
         }
         // check if the matching is full (should be, as the smaller set is completely matched
-        assert(Source.IsFull() == true);
+        assert(Source.isFull() == true);
         // now create a copy of the matching
         SimilMatching Dest(Source);
         // check the copy
         // - sizes of matched object
-        assert(Dest.GetObjectSize(0) == Source.GetObjectSize(0));
-        assert(Dest.GetObjectSize(1) == Source.GetObjectSize(1));
+        assert(Dest.getObjectSize(0) == Source.getObjectSize(0));
+        assert(Dest.getObjectSize(1) == Source.getObjectSize(1));
         // - the copy should be full, too
-        assert(Dest.IsFull() == true);
+        assert(Dest.isFull() == true);
         // - the copy should have exactly the same assignments in matching
         for (iObj = 0; iObj < iSize; iObj++)
@@ -240,18 +240,18 @@
             // check both directions: 0 -> 1
             // (all matched, (iObj, 2 * iObj))
-            assert(Dest.IsMatched(0, iObj) == true);
-            assert((2 * iObj) == Dest.GetMatchedIndex(0, iObj));
+            assert(Dest.isMatched(0, iObj) == true);
+            assert((2 * iObj) == Dest.getMatchedIndex(0, iObj));
             // and direction; 1 -> 0
             // (only even are matched, ( 2 * iObj, iObj))
             // for 2 * iObj (which are even): matched
-            assert(Dest.IsMatched(1, 2 * iObj) == true);
-            assert(iObj == Dest.GetMatchedIndex(1, 2 * iObj));
+            assert(Dest.isMatched(1, 2 * iObj) == true);
+            assert(iObj == Dest.getMatchedIndex(1, 2 * iObj));
             // for 2 * iObj + 1 (which are odd): unmatched
-            assert(Dest.IsMatched(1, 2 * iObj + 1) == false);
+            assert(Dest.isMatched(1, 2 * iObj + 1) == false);
         }
         // make it empty
-        Dest.Empty();
+        Dest.empty();
         // and check once more
-        assert(Dest.IsEmpty() == true);
+        assert(Dest.isEmpty() == true);
     }
 
@@ -273,5 +273,5 @@
 
     // matching is empty
-    assert(match1.IsEmpty() == true);
+    assert(match1.isEmpty() == true);
 
     // create matching - (i,i)
@@ -280,27 +280,27 @@
 
         // matching is not full
-        assert(match1.IsFull() == false);
+        assert(match1.isFull() == false);
 
         // these are not matched yet
-        assert(match1.IsMatched(0, i) == false);
-        assert(match1.IsMatched(1, i) == false);
+        assert(match1.isMatched(0, i) == false);
+        assert(match1.isMatched(1, i) == false);
 
         // now - match!
-        match1.Match(0, i, 1, i);
+        match1.match(0, i, 1, i);
 
         // matching is not empty
-        assert(match1.IsEmpty() == false);
+        assert(match1.isEmpty() == false);
 
         // now they are matched
-        assert(match1.IsMatched(0, i) == true);
-        assert(match1.IsMatched(1, i) == true);
+        assert(match1.isMatched(0, i) == true);
+        assert(match1.isMatched(1, i) == true);
 
         // check the matched index for object 0 and 1
-        assert(match1.GetMatchedIndex(0, i) == i);
-        assert(match1.GetMatchedIndex(1, i) == i);
+        assert(match1.getMatchedIndex(0, i) == i);
+        assert(match1.getMatchedIndex(1, i) == i);
     }
 
     // now matching have to be full
-    assert(match1.IsFull() == true);
+    assert(match1.isFull() == true);
 
     // check some symmetric matching
@@ -308,5 +308,5 @@
 
     // matching is empty
-    assert(match2.IsEmpty() == true);
+    assert(match2.isEmpty() == true);
 
     // create matching - (i, nSize1 - 1 - i)
@@ -315,27 +315,27 @@
 
         // matching is not full
-        assert(match2.IsFull() == false);
+        assert(match2.isFull() == false);
 
         // these are not matched yet
-        assert(match2.IsMatched(0, i) == false);
-        assert(match2.IsMatched(1, nSize1 - 1 - i) == false);
+        assert(match2.isMatched(0, i) == false);
+        assert(match2.isMatched(1, nSize1 - 1 - i) == false);
 
         // now - match (but use the opposite syntax)!
-        match2.Match(1, nSize1 - 1 - i, 0, i);
+        match2.match(1, nSize1 - 1 - i, 0, i);
 
         // matching is not empty
-        assert(match2.IsEmpty() == false);
+        assert(match2.isEmpty() == false);
 
         // now they are matched
-        assert(match2.IsMatched(0, i) == true);
-        assert(match2.IsMatched(1, nSize1 - 1 - i) == true);
+        assert(match2.isMatched(0, i) == true);
+        assert(match2.isMatched(1, nSize1 - 1 - i) == true);
 
         // check the matched index for object 0 and 1
-        assert(match2.GetMatchedIndex(0, i) == (nSize1 - 1 - i));
-        assert(match2.GetMatchedIndex(1, nSize1 - 1 - i) == i);
+        assert(match2.getMatchedIndex(0, i) == (nSize1 - 1 - i));
+        assert(match2.getMatchedIndex(1, nSize1 - 1 - i) == i);
     }
 
     // now matching have to be full
-    assert(match2.IsFull() == true);
+    assert(match2.isFull() == true);
 
     // check some asymmnetic matching, too
@@ -343,5 +343,5 @@
 
     // matching is empty
-    assert(match3.IsEmpty() == true);
+    assert(match3.isEmpty() == true);
 
     // create matching - (i, 2 * i)
@@ -350,30 +350,30 @@
 
         // matching is not full
-        assert(match3.IsFull() == false);
+        assert(match3.isFull() == false);
 
         // these are not matched yet
-        assert(match3.IsMatched(0, i) == false);
-        assert(match3.IsMatched(1, 2 * i) == false);
+        assert(match3.isMatched(0, i) == false);
+        assert(match3.isMatched(1, 2 * i) == false);
 
         // now - match (but use the opposite syntax)!
-        match3.Match(1, 2 * i, 0, i);
+        match3.match(1, 2 * i, 0, i);
 
         // matching is not empty
-        assert(match3.IsEmpty() == false);
+        assert(match3.isEmpty() == false);
 
         // now they are matched
-        assert(match3.IsMatched(0, i) == true);
-        assert(match3.IsMatched(1, 2 * i) == true);
+        assert(match3.isMatched(0, i) == true);
+        assert(match3.isMatched(1, 2 * i) == true);
 
         // but the odd elements of object 1 are not matched
-        assert(match3.IsMatched(1, 2 * i + 1) == false);
+        assert(match3.isMatched(1, 2 * i + 1) == false);
 
         // check the matched index for object 0 and 1
-        assert(match3.GetMatchedIndex(0, i) == 2 * i);
-        assert(match3.GetMatchedIndex(1, 2 * i) == i);
+        assert(match3.getMatchedIndex(0, i) == 2 * i);
+        assert(match3.getMatchedIndex(1, 2 * i) == i);
     }
 
     // now matching have to be full (because the smallest object has all elements matched).
-    assert(match3.IsFull() == true);
+    assert(match3.isFull() == true);
 
     return 0;
Index: /cpp/frams/model/similarity/EMD/emd.c
===================================================================
--- /cpp/frams/model/similarity/EMD/emd.c	(revision 1044)
+++ /cpp/frams/model/similarity/EMD/emd.c	(revision 1044)
@@ -0,0 +1,828 @@
+/*
+    emd.c
+
+    Last update: 3/14/98
+
+    An implementation of the Earth Movers Distance.
+    Based of the solution for the Transportation problem as described in
+    "Introduction to Mathematical Programming" by F. S. Hillier and 
+    G. J. Lieberman, McGraw-Hill, 1990.
+
+    Copyright (C) 1998 Yossi Rubner
+    Computer Science Department, Stanford University
+    E-Mail: rubner@cs.stanford.edu   URL: http://vision.stanford.edu/~rubner
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "emd.h"
+
+#define DEBUG_LEVEL 0
+/*
+ DEBUG_LEVEL:
+   0 = NO MESSAGES
+   1 = PRINT THE NUMBER OF ITERATIONS AND THE FINAL RESULT
+   2 = PRINT THE RESULT AFTER EVERY ITERATION
+   3 = PRINT ALSO THE FLOW AFTER EVERY ITERATION
+   4 = PRINT A LOT OF INFORMATION (PROBABLY USEFUL ONLY FOR THE AUTHOR)
+*/
+
+
+#define MAX_SIG_SIZE1  (MAX_SIG_SIZE+1)  /* FOR THE POSIBLE DUMMY FEATURE */
+
+/* NEW TYPES DEFINITION */
+
+/* node1_t IS USED FOR SINGLE-LINKED LISTS */
+typedef struct node1_t {
+  int i;
+  double val;
+  struct node1_t *Next;
+} node1_t;
+
+/* node1_t IS USED FOR DOUBLE-LINKED LISTS */
+typedef struct node2_t {
+  int i, j;
+  double val;
+  struct node2_t *NextC;               /* NEXT COLUMN */
+  struct node2_t *NextR;               /* NEXT ROW */
+} node2_t;
+
+
+
+/* GLOBAL VARIABLE DECLARATION */
+static int _n1, _n2;                          /* SIGNATURES SIZES */
+static float _C[MAX_SIG_SIZE1][MAX_SIG_SIZE1];/* THE COST MATRIX */
+static node2_t _X[MAX_SIG_SIZE1*2];            /* THE BASIC VARIABLES VECTOR */
+/* VARIABLES TO HANDLE _X EFFICIENTLY */
+static node2_t *_EndX, *_EnterX;
+static char _IsX[MAX_SIG_SIZE1][MAX_SIG_SIZE1];
+static node2_t *_RowsX[MAX_SIG_SIZE1], *_ColsX[MAX_SIG_SIZE1];
+static double _maxW;
+static float _maxC;
+
+/* DECLARATION OF FUNCTIONS */
+static float init(signature_t *Signature1, signature_t *Signature2,
+		  float (*Dist)(feature_t *, feature_t *));
+static void findBasicVariables(node1_t *U, node1_t *V);
+static int isOptimal(node1_t *U, node1_t *V);
+static int findLoop(node2_t **Loop);
+static void newSol();
+static void russel(double *S, double *D);
+static void addBasicVariable(int minI, int minJ, double *S, double *D, 
+			     node1_t *PrevUMinI, node1_t *PrevVMinJ,
+			     node1_t *UHead);
+#if DEBUG_LEVEL > 0
+static void printSolution();
+#endif
+
+
+/******************************************************************************
+float emd(signature_t *Signature1, signature_t *Signature2,
+	  float (*Dist)(feature_t *, feature_t *), flow_t *Flow, int *FlowSize)
+  
+where
+
+   Signature1, Signature2  Pointers to signatures that their distance we want
+              to compute.
+   Dist       Pointer to the ground distance. i.e. the function that computes
+              the distance between two features.
+   Flow       (Optional) Pointer to a vector of flow_t (defined in emd.h) 
+              where the resulting flow will be stored. Flow must have n1+n2-1
+              elements, where n1 and n2 are the sizes of the two signatures
+              respectively.
+              If NULL, the flow is not returned.
+   FlowSize   (Optional) Pointer to an integer where the number of elements in
+              Flow will be stored
+              
+******************************************************************************/
+
+float emd(signature_t *Signature1, signature_t *Signature2,
+	  float (*Dist)(feature_t *, feature_t *),
+	  flow_t *Flow, int *FlowSize)
+{
+  int itr;
+  double totalCost;
+  float w;
+  node2_t *XP;
+  flow_t *FlowP;
+  node1_t U[MAX_SIG_SIZE1], V[MAX_SIG_SIZE1];
+
+  w = init(Signature1, Signature2, Dist);
+
+#if DEBUG_LEVEL > 1
+  printf("\nINITIAL SOLUTION:\n");
+  printSolution();
+#endif
+ 
+  if (_n1 > 1 && _n2 > 1)  /* IF _n1 = 1 OR _n2 = 1 THEN WE ARE DONE */
+    {
+      for (itr = 1; itr < MAX_ITERATIONS; itr++)
+	{
+	  /* FIND BASIC VARIABLES */
+	  findBasicVariables(U, V);
+	  
+	  /* CHECK FOR OPTIMALITY */
+	  if (isOptimal(U, V))
+	    break;
+	  
+	  /* IMPROVE SOLUTION */
+	  newSol();
+	  
+#if DEBUG_LEVEL > 1
+	  printf("\nITERATION # %d \n", itr);
+	  printSolution();
+#endif
+	}
+
+      if (itr == MAX_ITERATIONS)
+	fprintf(stderr, "emd: Maximum number of iterations has been reached (%d)\n",
+		MAX_ITERATIONS);
+    }
+
+  /* COMPUTE THE TOTAL FLOW */
+  totalCost = 0;
+  if (Flow != NULL)
+    FlowP = Flow;
+  for(XP=_X; XP < _EndX; XP++)
+    {
+      if (XP == _EnterX)  /* _EnterX IS THE EMPTY SLOT */
+	continue;
+      if (XP->i == Signature1->n || XP->j == Signature2->n)  /* DUMMY FEATURE */
+	continue;
+      
+      if (XP->val == 0)  /* ZERO FLOW */
+	continue;
+
+      totalCost += (double)XP->val * _C[XP->i][XP->j];
+      if (Flow != NULL)
+	{
+	  FlowP->from = XP->i;
+	  FlowP->to = XP->j;
+	  FlowP->amount = XP->val;
+	  FlowP++;
+	}
+    }
+  if (Flow != NULL)
+    *FlowSize = FlowP-Flow;
+
+#if DEBUG_LEVEL > 0
+  printf("\n*** OPTIMAL SOLUTION (%d ITERATIONS): %f ***\n", itr, totalCost);
+#endif
+
+  /* RETURN THE NORMALIZED COST == EMD */
+  return (float)(totalCost / w);
+}
+
+
+
+
+
+/**********************
+   init
+**********************/
+static float init(signature_t *Signature1, signature_t *Signature2, 
+		  float (*Dist)(feature_t *, feature_t *))
+{
+  int i, j;
+  double sSum, dSum, diff;
+  feature_t *P1, *P2;
+  double S[MAX_SIG_SIZE1], D[MAX_SIG_SIZE1];
+ 
+  _n1 = Signature1->n;
+  _n2 = Signature2->n;
+
+  if (_n1 > MAX_SIG_SIZE || _n2 > MAX_SIG_SIZE)
+    {
+      fprintf(stderr, "emd: Signature size is limited to %d\n", MAX_SIG_SIZE);
+      exit(1);
+    }
+  
+  /* COMPUTE THE DISTANCE MATRIX */
+  _maxC = 0;
+  for(i=0, P1=Signature1->Features; i < _n1; i++, P1++)
+    for(j=0, P2=Signature2->Features; j < _n2; j++, P2++) 
+      {
+	_C[i][j] = Dist(P1, P2);
+	if (_C[i][j] > _maxC)
+	  _maxC = _C[i][j];
+      }
+	
+  /* SUM UP THE SUPPLY AND DEMAND */
+  sSum = 0.0;
+  for(i=0; i < _n1; i++)
+    {
+      S[i] = Signature1->Weights[i];
+      sSum += Signature1->Weights[i];
+      _RowsX[i] = NULL;
+    }
+  dSum = 0.0;
+  for(j=0; j < _n2; j++)
+    {
+      D[j] = Signature2->Weights[j];
+      dSum += Signature2->Weights[j];
+      _ColsX[j] = NULL;
+    }
+
+  /* IF SUPPLY DIFFERENT THAN THE DEMAND, ADD A ZERO-COST DUMMY CLUSTER */
+  diff = sSum - dSum;
+  if (fabs(diff) >= EPSILON * sSum)
+    {
+      if (diff < 0.0)
+	{
+	  for (j=0; j < _n2; j++)
+	    _C[_n1][j] = 0;
+	  S[_n1] = -diff;
+	  _RowsX[_n1] = NULL;
+	  _n1++;
+	}
+      else
+	{
+	  for (i=0; i < _n1; i++)
+	    _C[i][_n2] = 0;
+	  D[_n2] = diff;
+	  _ColsX[_n2] = NULL;
+	  _n2++;
+	}
+    }
+
+  /* INITIALIZE THE BASIC VARIABLE STRUCTURES */
+  for (i=0; i < _n1; i++)
+    for (j=0; j < _n2; j++)
+	_IsX[i][j] = 0;
+  _EndX = _X;
+   
+  _maxW = sSum > dSum ? sSum : dSum;
+
+  /* FIND INITIAL SOLUTION */
+  russel(S, D);
+
+  _EnterX = _EndX++;  /* AN EMPTY SLOT (ONLY _n1+_n2-1 BASIC VARIABLES) */
+
+  return sSum > dSum ? dSum : sSum;
+}
+
+
+/**********************
+    findBasicVariables
+ **********************/
+static void findBasicVariables(node1_t *U, node1_t *V)
+{
+  int i, j, found;
+  int UfoundNum, VfoundNum;
+  node1_t u0Head, u1Head, *CurU, *PrevU;
+  node1_t v0Head, v1Head, *CurV, *PrevV;
+
+  /* INITIALIZE THE ROWS LIST (U) AND THE COLUMNS LIST (V) */
+  u0Head.Next = CurU = U;
+  for (i=0; i < _n1; i++)
+    {
+      CurU->i = i;
+      CurU->Next = CurU+1;
+      CurU++;
+    }
+  (--CurU)->Next = NULL;
+  u1Head.Next = NULL;
+
+  CurV = V+1;
+  v0Head.Next = _n2 > 1 ? V+1 : NULL;
+  for (j=1; j < _n2; j++)
+    {
+      CurV->i = j;
+      CurV->Next = CurV+1;
+      CurV++;
+    }
+  (--CurV)->Next = NULL;
+  v1Head.Next = NULL;
+
+  /* THERE ARE _n1+_n2 VARIABLES BUT ONLY _n1+_n2-1 INDEPENDENT EQUATIONS,
+     SO SET V[0]=0 */
+  V[0].i = 0;
+  V[0].val = 0;
+  v1Head.Next = V;
+  v1Head.Next->Next = NULL;
+
+  /* LOOP UNTIL ALL VARIABLES ARE FOUND */
+  UfoundNum=VfoundNum=0;
+  while (UfoundNum < _n1 || VfoundNum < _n2)
+    {
+
+#if DEBUG_LEVEL > 3
+      printf("UfoundNum=%d/%d,VfoundNum=%d/%d\n",UfoundNum,_n1,VfoundNum,_n2);
+      printf("U0=");
+      for(CurU = u0Head.Next; CurU != NULL; CurU = CurU->Next)
+	printf("[%d]",CurU-U);
+      printf("\n");
+      printf("U1=");
+      for(CurU = u1Head.Next; CurU != NULL; CurU = CurU->Next)
+	printf("[%d]",CurU-U);
+      printf("\n");
+      printf("V0=");
+      for(CurV = v0Head.Next; CurV != NULL; CurV = CurV->Next)
+	printf("[%d]",CurV-V);
+      printf("\n");
+      printf("V1=");
+      for(CurV = v1Head.Next; CurV != NULL; CurV = CurV->Next)
+	printf("[%d]",CurV-V);
+      printf("\n\n");
+#endif
+      
+      found = 0;
+      if (VfoundNum < _n2)
+	{
+	  /* LOOP OVER ALL MARKED COLUMNS */
+	  PrevV = &v1Head;
+	  for (CurV=v1Head.Next; CurV != NULL; CurV=CurV->Next)
+	    {
+	      j = CurV->i;
+	      /* FIND THE VARIABLES IN COLUMN j */
+	      PrevU = &u0Head;
+	      for (CurU=u0Head.Next; CurU != NULL; CurU=CurU->Next)
+		{
+		  i = CurU->i;
+		  if (_IsX[i][j])
+		    {
+		      /* COMPUTE U[i] */
+		      CurU->val = _C[i][j] - CurV->val;
+		      /* ...AND ADD IT TO THE MARKED LIST */
+		      PrevU->Next = CurU->Next;
+		      CurU->Next = u1Head.Next != NULL ? u1Head.Next : NULL;
+		      u1Head.Next = CurU;
+		      CurU = PrevU;
+		    }
+		  else
+		    PrevU = CurU;
+		}
+	      PrevV->Next = CurV->Next;
+	      VfoundNum++;
+	      found = 1;
+	    }
+	}
+     if (UfoundNum < _n1)
+	{
+	  /* LOOP OVER ALL MARKED ROWS */
+	  PrevU = &u1Head;
+	  for (CurU=u1Head.Next; CurU != NULL; CurU=CurU->Next)
+	    {
+	      i = CurU->i;
+	      /* FIND THE VARIABLES IN ROWS i */
+	      PrevV = &v0Head;
+	      for (CurV=v0Head.Next; CurV != NULL; CurV=CurV->Next)
+		{
+		  j = CurV->i;
+		  if (_IsX[i][j])
+		    {
+		      /* COMPUTE V[j] */
+		      CurV->val = _C[i][j] - CurU->val;
+		      /* ...AND ADD IT TO THE MARKED LIST */
+		      PrevV->Next = CurV->Next;
+		      CurV->Next = v1Head.Next != NULL ? v1Head.Next: NULL;
+		      v1Head.Next = CurV;
+		      CurV = PrevV;
+		    }
+		  else
+		    PrevV = CurV;
+		}
+	      PrevU->Next = CurU->Next;
+	      UfoundNum++;
+	      found = 1;
+	    }
+	}
+     if (! found)
+       {
+	 fprintf(stderr, "emd: Unexpected error in findBasicVariables!\n");
+	 fprintf(stderr, "This typically happens when the EPSILON defined in\n");
+	 fprintf(stderr, "emd.h is not right for the scale of the problem.\n");
+	 exit(1);
+       }
+    }
+}
+
+
+
+
+/**********************
+    isOptimal
+ **********************/
+static int isOptimal(node1_t *U, node1_t *V)
+{    
+  double delta, deltaMin;
+  int i, j, minI, minJ;
+
+  /* FIND THE MINIMAL Cij-Ui-Vj OVER ALL i,j */
+  deltaMin = INFINITY;
+  for(i=0; i < _n1; i++)
+    for(j=0; j < _n2; j++)
+      if (! _IsX[i][j])
+	{
+	  delta = _C[i][j] - U[i].val - V[j].val;
+	  if (deltaMin > delta)
+	    {
+              deltaMin = delta;
+	      minI = i;
+	      minJ = j;
+	    }
+	}
+
+#if DEBUG_LEVEL > 3
+  printf("deltaMin=%f\n", deltaMin);
+#endif
+
+   if (deltaMin == INFINITY)
+     {
+       fprintf(stderr, "emd: Unexpected error in isOptimal.\n");
+       exit(0);
+     }
+   
+   _EnterX->i = minI;
+   _EnterX->j = minJ;
+   
+   /* IF NO NEGATIVE deltaMin, WE FOUND THE OPTIMAL SOLUTION */
+   return deltaMin >= -EPSILON * _maxC;
+
+/*
+   return deltaMin >= -EPSILON;
+ */
+}
+
+
+/**********************
+    newSol
+**********************/
+static void newSol()
+{
+    int i, j, k;
+    double xMin;
+    int steps;
+    node2_t *Loop[2*MAX_SIG_SIZE1], *CurX, *LeaveX;
+ 
+#if DEBUG_LEVEL > 3
+    printf("EnterX = (%d,%d)\n", _EnterX->i, _EnterX->j);
+#endif
+
+    /* ENTER THE NEW BASIC VARIABLE */
+    i = _EnterX->i;
+    j = _EnterX->j;
+    _IsX[i][j] = 1;
+    _EnterX->NextC = _RowsX[i];
+    _EnterX->NextR = _ColsX[j];
+    _EnterX->val = 0;
+    _RowsX[i] = _EnterX;
+    _ColsX[j] = _EnterX;
+
+    /* FIND A CHAIN REACTION */
+    steps = findLoop(Loop);
+
+    /* FIND THE LARGEST VALUE IN THE LOOP */
+    xMin = INFINITY;
+    for (k=1; k < steps; k+=2)
+      {
+	if (Loop[k]->val < xMin)
+	  {
+	    LeaveX = Loop[k];
+	    xMin = Loop[k]->val;
+	  }
+      }
+
+    /* UPDATE THE LOOP */
+    for (k=0; k < steps; k+=2)
+      {
+	Loop[k]->val += xMin;
+	Loop[k+1]->val -= xMin;
+      }
+
+#if DEBUG_LEVEL > 3
+    printf("LeaveX = (%d,%d)\n", LeaveX->i, LeaveX->j);
+#endif
+
+    /* REMOVE THE LEAVING BASIC VARIABLE */
+    i = LeaveX->i;
+    j = LeaveX->j;
+    _IsX[i][j] = 0;
+    if (_RowsX[i] == LeaveX)
+      _RowsX[i] = LeaveX->NextC;
+    else
+      for (CurX=_RowsX[i]; CurX != NULL; CurX = CurX->NextC)
+	if (CurX->NextC == LeaveX)
+	  {
+	    CurX->NextC = CurX->NextC->NextC;
+	    break;
+	  }
+    if (_ColsX[j] == LeaveX)
+      _ColsX[j] = LeaveX->NextR;
+    else
+      for (CurX=_ColsX[j]; CurX != NULL; CurX = CurX->NextR)
+	if (CurX->NextR == LeaveX)
+	  {
+	    CurX->NextR = CurX->NextR->NextR;
+	    break;
+	  }
+
+    /* SET _EnterX TO BE THE NEW EMPTY SLOT */
+    _EnterX = LeaveX;
+}
+
+
+
+/**********************
+    findLoop
+**********************/
+static int findLoop(node2_t **Loop)
+{
+  int i, steps;
+  node2_t **CurX, *NewX;
+  char IsUsed[2*MAX_SIG_SIZE1]; 
+ 
+  for (i=0; i < _n1+_n2; i++)
+    IsUsed[i] = 0;
+
+  CurX = Loop;
+  NewX = *CurX = _EnterX;
+  IsUsed[_EnterX-_X] = 1;
+  steps = 1;
+
+  do
+    {
+      if (steps%2 == 1)
+	{
+	  /* FIND AN UNUSED X IN THE ROW */
+	  NewX = _RowsX[NewX->i];
+	  while (NewX != NULL && IsUsed[NewX-_X])
+	    NewX = NewX->NextC;
+	}
+      else
+	{
+	  /* FIND AN UNUSED X IN THE COLUMN, OR THE ENTERING X */
+	  NewX = _ColsX[NewX->j];
+	  while (NewX != NULL && IsUsed[NewX-_X] && NewX != _EnterX)
+	    NewX = NewX->NextR;
+	  if (NewX == _EnterX)
+	    break;
+ 	}
+
+     if (NewX != NULL)  /* FOUND THE NEXT X */
+       {
+	 /* ADD X TO THE LOOP */
+	 *++CurX = NewX;
+	 IsUsed[NewX-_X] = 1;
+	 steps++;
+#if DEBUG_LEVEL > 3
+	 printf("steps=%d, NewX=(%d,%d)\n", steps, NewX->i, NewX->j);    
+#endif
+       }
+     else  /* DIDN'T FIND THE NEXT X */
+       {
+	 /* BACKTRACK */
+	 do
+	   {
+	     NewX = *CurX;
+	     do 
+	       {
+		 if (steps%2 == 1)
+		   NewX = NewX->NextR;
+		 else
+		   NewX = NewX->NextC;
+	       } while (NewX != NULL && IsUsed[NewX-_X]);
+	     
+	     if (NewX == NULL)
+	       {
+		 IsUsed[*CurX-_X] = 0;
+		 CurX--;
+		 steps--;
+	       }
+	 } while (NewX == NULL && CurX >= Loop);
+	 
+#if DEBUG_LEVEL > 3
+	 printf("BACKTRACKING TO: steps=%d, NewX=(%d,%d)\n",
+		steps, NewX->i, NewX->j);    
+#endif
+           IsUsed[*CurX-_X] = 0;
+	   *CurX = NewX;
+	   IsUsed[NewX-_X] = 1;
+       }     
+    } while(CurX >= Loop);
+  
+  if (CurX == Loop)
+    {
+      fprintf(stderr, "emd: Unexpected error in findLoop!\n");
+      exit(1);
+    }
+#if DEBUG_LEVEL > 3
+  printf("FOUND LOOP:\n");
+  for (i=0; i < steps; i++)
+    printf("%d: (%d,%d)\n", i, Loop[i]->i, Loop[i]->j);
+#endif
+
+  return steps;
+}
+
+
+
+/**********************
+    russel
+**********************/
+static void russel(double *S, double *D)
+{
+  int i, j, found, minI, minJ;
+  double deltaMin, oldVal, diff;
+  double Delta[MAX_SIG_SIZE1][MAX_SIG_SIZE1];
+  node1_t Ur[MAX_SIG_SIZE1], Vr[MAX_SIG_SIZE1];
+  node1_t uHead, *CurU, *PrevU;
+  node1_t vHead, *CurV, *PrevV;
+  node1_t *PrevUMinI, *PrevVMinJ, *Remember;
+
+  /* INITIALIZE THE ROWS LIST (Ur), AND THE COLUMNS LIST (Vr) */
+  uHead.Next = CurU = Ur;
+  for (i=0; i < _n1; i++)
+    {
+      CurU->i = i;
+      CurU->val = -INFINITY;
+      CurU->Next = CurU+1;
+      CurU++;
+    }
+  (--CurU)->Next = NULL;
+  
+  vHead.Next = CurV = Vr;
+  for (j=0; j < _n2; j++)
+    {
+      CurV->i = j;
+      CurV->val = -INFINITY;
+      CurV->Next = CurV+1;
+      CurV++;
+    }
+  (--CurV)->Next = NULL;
+  
+  /* FIND THE MAXIMUM ROW AND COLUMN VALUES (Ur[i] AND Vr[j]) */
+  for(i=0; i < _n1 ; i++)
+    for(j=0; j < _n2 ; j++)
+      {
+	float v;
+	v = _C[i][j];
+	if (Ur[i].val <= v)
+	  Ur[i].val = v;
+	if (Vr[j].val <= v)
+	  Vr[j].val = v;
+      }
+  
+  /* COMPUTE THE Delta MATRIX */
+  for(i=0; i < _n1 ; i++)
+    for(j=0; j < _n2 ; j++)
+      Delta[i][j] = _C[i][j] - Ur[i].val - Vr[j].val;
+
+  /* FIND THE BASIC VARIABLES */
+  do
+    {
+#if DEBUG_LEVEL > 3
+      printf("Ur=");
+      for(CurU = uHead.Next; CurU != NULL; CurU = CurU->Next)
+	printf("[%d]",CurU-Ur);
+      printf("\n");
+      printf("Vr=");
+      for(CurV = vHead.Next; CurV != NULL; CurV = CurV->Next)
+	printf("[%d]",CurV-Vr);
+      printf("\n");
+      printf("\n\n");
+#endif
+ 
+      /* FIND THE SMALLEST Delta[i][j] */
+      found = 0; 
+      deltaMin = INFINITY;      
+      PrevU = &uHead;
+      for (CurU=uHead.Next; CurU != NULL; CurU=CurU->Next)
+	{
+	  int i;
+	  i = CurU->i;
+	  PrevV = &vHead;
+	  for (CurV=vHead.Next; CurV != NULL; CurV=CurV->Next)
+	    {
+	      int j;
+	      j = CurV->i;
+	      if (deltaMin > Delta[i][j])
+		{
+		  deltaMin = Delta[i][j];
+		  minI = i;
+		  minJ = j;
+		  PrevUMinI = PrevU;
+		  PrevVMinJ = PrevV;
+		  found = 1;
+		}
+	      PrevV = CurV;
+	    }
+	  PrevU = CurU;
+	}
+      
+      if (! found)
+	break;
+
+      /* ADD X[minI][minJ] TO THE BASIS, AND ADJUST SUPPLIES AND COST */
+      Remember = PrevUMinI->Next;
+      addBasicVariable(minI, minJ, S, D, PrevUMinI, PrevVMinJ, &uHead);
+
+      /* UPDATE THE NECESSARY Delta[][] */
+      if (Remember == PrevUMinI->Next)  /* LINE minI WAS DELETED */
+	{
+	  for (CurV=vHead.Next; CurV != NULL; CurV=CurV->Next)
+	    {
+	      int j;
+	      j = CurV->i;
+	      if (CurV->val == _C[minI][j])  /* COLUMN j NEEDS UPDATING */
+		{
+		  /* FIND THE NEW MAXIMUM VALUE IN THE COLUMN */
+		  oldVal = CurV->val;
+		  CurV->val = -INFINITY;
+		  for (CurU=uHead.Next; CurU != NULL; CurU=CurU->Next)
+		    {
+		      int i;
+		      i = CurU->i;
+		      if (CurV->val <= _C[i][j])
+			CurV->val = _C[i][j];
+		    }
+		  
+		  /* IF NEEDED, ADJUST THE RELEVANT Delta[*][j] */
+		  diff = oldVal - CurV->val;
+		  if (fabs(diff) < EPSILON * _maxC)
+		    for (CurU=uHead.Next; CurU != NULL; CurU=CurU->Next)
+		      Delta[CurU->i][j] += diff;
+		}
+	    }
+	}
+      else  /* COLUMN minJ WAS DELETED */
+	{
+	  for (CurU=uHead.Next; CurU != NULL; CurU=CurU->Next)
+	    {
+	      int i;
+	      i = CurU->i;
+	      if (CurU->val == _C[i][minJ])  /* ROW i NEEDS UPDATING */
+		{
+		  /* FIND THE NEW MAXIMUM VALUE IN THE ROW */
+		  oldVal = CurU->val;
+		  CurU->val = -INFINITY;
+		  for (CurV=vHead.Next; CurV != NULL; CurV=CurV->Next)
+		    {
+		      int j;
+		      j = CurV->i;
+		      if(CurU->val <= _C[i][j])
+			CurU->val = _C[i][j];
+		    }
+		  
+		  /* If NEEDED, ADJUST THE RELEVANT Delta[i][*] */
+		  diff = oldVal - CurU->val;
+		  if (fabs(diff) < EPSILON * _maxC)
+		    for (CurV=vHead.Next; CurV != NULL; CurV=CurV->Next)
+		      Delta[i][CurV->i] += diff;
+		}
+	    }
+	}
+    } while (uHead.Next != NULL || vHead.Next != NULL);
+}
+
+
+
+
+/**********************
+    addBasicVariable
+**********************/
+static void addBasicVariable(int minI, int minJ, double *S, double *D, 
+			     node1_t *PrevUMinI, node1_t *PrevVMinJ,
+			     node1_t *UHead)
+{
+  double T;
+  
+  if (fabs(S[minI]-D[minJ]) <= EPSILON * _maxW)  /* DEGENERATE CASE */
+    {
+      T = S[minI];
+      S[minI] = 0;
+      D[minJ] -= T; 
+    }
+  else if (S[minI] < D[minJ])  /* SUPPLY EXHAUSTED */
+    {
+      T = S[minI];
+      S[minI] = 0;
+      D[minJ] -= T; 
+    }
+  else  /* DEMAND EXHAUSTED */
+    {
+      T = D[minJ];
+      D[minJ] = 0; 
+      S[minI] -= T; 
+    }
+
+  /* X(minI,minJ) IS A BASIC VARIABLE */
+  _IsX[minI][minJ] = 1; 
+
+  _EndX->val = T;
+  _EndX->i = minI;
+  _EndX->j = minJ;
+  _EndX->NextC = _RowsX[minI];
+  _EndX->NextR = _ColsX[minJ];
+  _RowsX[minI] = _EndX;
+  _ColsX[minJ] = _EndX;
+  _EndX++;
+
+  /* DELETE SUPPLY ROW ONLY IF THE EMPTY, AND IF NOT LAST ROW */
+  if (S[minI] == 0 && UHead->Next->Next != NULL)
+    PrevUMinI->Next = PrevUMinI->Next->Next;  /* REMOVE ROW FROM LIST */
+  else
+    PrevVMinJ->Next = PrevVMinJ->Next->Next;  /* REMOVE COLUMN FROM LIST */
+}
Index: /cpp/frams/model/similarity/EMD/emd.h
===================================================================
--- /cpp/frams/model/similarity/EMD/emd.h	(revision 1044)
+++ /cpp/frams/model/similarity/EMD/emd.h	(revision 1044)
@@ -0,0 +1,54 @@
+#ifndef _EMD_H
+#define _EMD_H
+/*
+    emd.h
+
+    Last update: 3/24/98
+
+    An implementation of the Earth Movers Distance.
+    Based of the solution for the Transportation problem as described in
+    "Introduction to Mathematical Programming" by F. S. Hillier and 
+    G. J. Lieberman, McGraw-Hill, 1990.
+
+    Copyright (C) 1998 Yossi Rubner
+    Computer Science Department, Stanford University
+    E-Mail: rubner@cs.stanford.edu   URL: http://vision.stanford.edu/~rubner
+*/
+
+/* DEFINITIONS */
+#define MAX_SIG_SIZE   1000
+#define MAX_ITERATIONS 500
+//#define INFINITY       1e20
+#define EPSILON        1e-6
+
+/*****************************************************************************/
+/* feature_t SHOULD BE MODIFIED BY THE USER TO REFLECT THE FEATURE TYPE      */
+//typedef struct {
+//   double X,Y,Z;
+//}
+typedef double feature_t;
+/*****************************************************************************/
+
+
+typedef struct
+{
+  int n;                /* Number of features in the signature */
+  feature_t *Features;  /* Pointer to the features vector */
+  float *Weights;       /* Pointer to the weights of the features */
+} signature_t;
+
+
+typedef struct
+{
+  int from;             /* Feature number in signature 1 */
+  int to;               /* Feature number in signature 2 */
+  float amount;         /* Amount of flow from "from" to "to" */
+} flow_t;
+
+
+
+float emd(signature_t *Signature1, signature_t *Signature2,
+	  float (*func)(feature_t *, feature_t *),
+	  flow_t *Flow, int *FlowSize);
+
+#endif
Index: /cpp/frams/model/similarity/measure-distribution.cpp
===================================================================
--- /cpp/frams/model/similarity/measure-distribution.cpp	(revision 1044)
+++ /cpp/frams/model/similarity/measure-distribution.cpp	(revision 1044)
@@ -0,0 +1,300 @@
+// This file is a part of Framsticks SDK.  http://www.framsticks.com/
+// Copyright (C) 1999-2020  Maciej Komosinski and Szymon Ulatowski.
+// See LICENSE.txt for details.
+
+#include "measure-distribution.h"
+#include <common/nonstd_math.h>
+#include <limits>
+#include "EMD/emd.c"
+#include <iostream>
+
+#define PI 3.1415926535
+
+#define FIELDSTRUCT SimilMeasureDistribution
+
+static ParamEntry simil_distribution_paramtab[] = {
+		{ "Similarity: distribution", 1, 4, "SimilMeasureDistribution", "Evaluates morphological dissimilarity using distribution measure.", },
+		{ "simil_density", 0, 0, "Density of surface sampling", "f 1 100 10", FIELD(density), "", },
+		{ "simil_bin_num", 0, 0, "Number of bins", "d 1 1000 128", FIELD(bin_num), "", },
+		{ "simil_samples_num", 0, 0, "Number of samples", "d 1 1048576 1048576", FIELD(samples_num), "", },
+		{ "evaluateDistance", 0, PARAM_DONTSAVE | PARAM_USERHIDDEN, "evaluate model dissimilarity", "p f(oGeno,oGeno)", PROCEDURE(p_evaldistance), "Calculates dissimilarity between two models created from Geno objects.", },
+		{ 0, },
+};
+
+#undef FIELDSTRUCT
+
+SimilMeasureDistribution::SimilMeasureDistribution() : localpar(simil_distribution_paramtab, this)
+{
+	localpar.setDefault();
+	SimilMeasureDistribution::distribution_fun = &SimilMeasureDistribution::D2; //D1 and D2 are the best descriptors
+}
+
+double SimilMeasureDistribution::getDistance()
+{
+	double dist = 0;
+	for (int i = 0; i < 2; i++)
+	{
+		funs[i] = new std::pair<double, float>[bin_num]();
+		for (int j = 0; j < bin_num; j++)
+			funs[i][j] = std::make_pair(0, 0);
+	}
+	
+	for (int i = 0; i < 2; i++)
+		sst_models[i] = new SolidsShapeTypeModel((*models[i]));
+	
+	SimilMeasureDistribution::calculateFuns();	
+	dist = SimilMeasureDistribution::compareFuns();
+	
+	for (int i = 0; i < 2; i++)
+	{
+		SAFEDELETE(sst_models[i]);
+		SAFEDELETEARRAY(funs[i]);
+	}
+	return dist;
+}
+
+int SimilMeasureDistribution::setParams(std::vector<double> params)
+{
+	for (unsigned int i = 0; i < params.size(); i++)
+		if (params.at(i) <= 0)
+		{
+			logPrintf("SimilDistributionMeasure", "setParams", LOG_ERROR, "Param values should be larger than 0.");
+			return -1;
+		}
+	
+	density = params.at(0);
+	bin_num = params.at(1);
+	samples_num = params.at(2);
+	
+	return 0;
+}
+
+void SimilMeasureDistribution::calculateFun(std::pair<double, float> *fun, Model &sampled)
+{
+	int size = sampled.getPartCount();
+	int samples_taken = samples_num;
+
+	//Check if total number of points pairs is smaller than samples number
+	//but first, prevent exceeding int limits
+	if (size < (int) sqrt((double) std::numeric_limits<int>::max()))
+		samples_taken = min(samples_num, size*size);
+
+	//Get sampled distribution
+	std::vector<double> dist_vect = (this->*SimilMeasureDistribution::distribution_fun)(samples_taken, &sampled);
+
+	auto result = std::minmax_element(dist_vect.begin(), dist_vect.end());
+	double min = *result.first;
+	double max = *result.second;
+
+	//Create histogram
+	float hist[bin_num] = {};	
+	int ind = 0;
+
+	for (unsigned int j = 0; j < dist_vect.size(); j++)
+	{
+		ind = (int) std::floor((dist_vect.at(j)-min)*1/(max-min)*bin_num);
+		if (ind <= (bin_num-1))
+			hist[ind] += 1;
+		else if (ind == bin_num)
+			hist[bin_num-1] += 1;
+	}
+
+	//Create pairs
+	for (int j = 0; j < bin_num; j++)
+	{
+		fun[j] = std::make_pair(min+(max-min)/bin_num*(j+0.5), hist[j]);
+	}
+
+	//Normalize
+	float total_mass = 0;
+	for (int j = 0; j < bin_num; j++)
+    {
+        total_mass += fun[j].second;
+    }
+
+	for (int j = 0; j < bin_num; j++)
+		fun[j].second /= total_mass;
+}
+
+void SimilMeasureDistribution::calculateFuns()
+{
+	for (int i = 0; i < 2; i++)
+	{
+		Model sampled = SimilMeasureDistribution::sampleSurface(&sst_models[i]->getModel(), density);
+		SimilMeasureDistribution::calculateFun(funs[i], sampled);
+	}
+}
+
+double SimilMeasureDistribution::compareFuns()
+{
+	return SimilMeasureDistribution::EMD(funs[0], funs[1]);
+}
+
+vector<double> SimilMeasureDistribution::D1(int samples_taken, Model *sampled)
+{
+	vector<double> dist_vect;
+	int size = sampled->getPartCount();
+	double x = 0;
+	double y = 0;
+	double z = 0;
+	
+	for (int i = 0; i < size; i++)
+	{
+		Pt3D pos = sampled->getPart(i)->p;
+		x += pos.x;
+		y += pos.y;
+		z += pos.z;
+	}
+	
+	x = x/size;
+	y = y/size;
+	z = z/size;
+	
+	Pt3D centroid = {x, y, z};
+	
+	for (int i = 0; i < samples_taken; i++)
+	{
+		int p1 = rndUint(size);
+		double dist = sampled->getPart(p1)->p.distanceTo(centroid);
+		if (dist > 0)
+			dist_vect.push_back(dist);
+	}
+	
+	return dist_vect;
+}
+
+vector<double> SimilMeasureDistribution::D2(int samples_taken, Model *sampled)
+{
+	vector<double> dist_vect;
+	int size = sampled->getPartCount();
+	for (int i = 0; i < samples_taken; i++)
+	{
+		int p1 = rndUint(size);
+		int p2 = rndUint(size);
+		double dist = sampled->getPart(p1)->p.distanceTo(sampled->getPart(p2)->p);
+		if (dist > 0)
+			dist_vect.push_back(dist);
+	}
+	
+	return dist_vect;
+}
+
+vector<double> SimilMeasureDistribution::D3(int samples_taken, Model *sampled)
+{
+	vector<double> dist_vect;
+	int size = sampled->getPartCount();
+	for (int i = 0; i < samples_taken; i++)
+	{
+		int p1 = rndUint(size);
+		int p2 = rndUint(size);
+		int p3 = rndUint(size);
+		
+		Pt3D v(sampled->getPart(p2)->p);
+		Pt3D w(sampled->getPart(p3)->p);
+		v -= sampled->getPart(p1)->p;
+		w -= sampled->getPart(p1)->p;
+		Pt3D cross_prod(0);
+		cross_prod.vectorProduct(v, w);
+		
+		double dist = 0.5 * cross_prod.length();
+		if (dist > 0)
+			dist_vect.push_back(dist);
+	}
+	
+	return dist_vect;
+}
+
+vector<double> SimilMeasureDistribution::D4(int samples_taken, Model *sampled)
+{
+	vector<double> dist_vect;
+	int size = sampled->getPartCount();
+	for (int i = 0; i < samples_taken; i++)
+	{
+		int a = rndUint(size);
+		int b = rndUint(size);
+		int c = rndUint(size);
+		int d = rndUint(size);
+		
+		Pt3D ad(sampled->getPart(a)->p);
+		Pt3D bd(sampled->getPart(b)->p);
+		Pt3D cd(sampled->getPart(c)->p);
+		
+		ad -= sampled->getPart(d)->p;
+		bd -= sampled->getPart(d)->p;
+		cd -= sampled->getPart(d)->p;
+		
+		Pt3D cross_prod(0);
+		cross_prod.vectorProduct(bd, cd);
+		cross_prod.entrywiseProduct(ad);
+		
+		double dist = cross_prod.length()/6;
+		if (dist > 0)
+			dist_vect.push_back(dist);
+	}
+	
+	return dist_vect;
+}
+
+vector<double> SimilMeasureDistribution::A3(int samples_taken, Model *sampled)
+{
+	vector<double> dist_vect;
+	int size = sampled->getPartCount();
+	for (int i = 0; i < samples_taken; i++)
+	{
+		int p1 = rndUint(size);
+		int p2 = rndUint(size);
+		int p3 = rndUint(size);
+		double a = sampled->getPart(p1)->p.distanceTo(sampled->getPart(p3)->p);
+		double b = sampled->getPart(p3)->p.distanceTo(sampled->getPart(p2)->p);
+		double c = sampled->getPart(p1)->p.distanceTo(sampled->getPart(p2)->p);
+		double beta = acos((a*a + b*b - c*c)/(2*a*b));
+	
+		if (!std::isnan(beta))
+			dist_vect.push_back(beta);
+	}
+	
+	return dist_vect;
+}
+
+
+float dist(feature_t* F1, feature_t* F2)
+{ 
+	return abs((*F1)-(*F2)); 
+}
+
+
+void SimilMeasureDistribution::fillPointsWeights(std::pair<double, float> *fun, feature_t *points, float *weights)
+{
+	for (int j = 0; j < bin_num; j++)
+	{
+		points[j] = {fun[j].first};
+		weights[j] = fun[j].second;
+	}
+}
+
+double SimilMeasureDistribution::EMD(std::pair<double, float> *fun1, std::pair<double, float> *fun2)
+{
+	feature_t *points[2];
+	float *weights[2];
+	
+	for (int i = 0; i < 2; i++)
+	{
+		points[i] = new feature_t[bin_num];
+		weights[i] = new float[bin_num]();
+	}
+	SimilMeasureDistribution::fillPointsWeights(fun1, points[0], weights[0]);
+	SimilMeasureDistribution::fillPointsWeights(fun2, points[1], weights[1]);
+	
+	signature_t sig1 = {bin_num, points[0], weights[0]},
+	sig2 = {bin_num, points[1], weights[1]};
+
+	float e = emd(&sig1, &sig2, dist, 0, 0);
+	
+	for (int i = 0; i < 2; i++)
+	{
+		delete[] points[i];
+		delete[] weights[i];
+	}
+
+	return e;
+}
Index: /cpp/frams/model/similarity/measure-distribution.h
===================================================================
--- /cpp/frams/model/similarity/measure-distribution.h	(revision 1044)
+++ /cpp/frams/model/similarity/measure-distribution.h	(revision 1044)
@@ -0,0 +1,42 @@
+// This file is a part of Framsticks SDK.  http://www.framsticks.com/
+// Copyright (C) 1999-2020  Maciej Komosinski and Szymon Ulatowski.
+// See LICENSE.txt for details.
+
+#ifndef DISTRIBUTION_MEASURE_H
+#define DISTRIBUTION_MEASURE_H
+
+#include "simil-measure.h"
+#include "EMD/emd.h"
+
+class SimilMeasureDistribution : public SimilMeasure
+{
+public:
+	SimilMeasureDistribution();
+	~SimilMeasureDistribution(){};
+	int setParams(std::vector<double> params);
+	void calculateFuns();
+	void calculateFun(std::pair<double, float> *fun, Model &sampled);
+	double compareFuns();
+	double EMD(std::pair<double, float> *fun1, std::pair<double, float> *fun2);
+	double density;
+	int samples_num;
+	int bin_num;
+	/// Interface to local parameters
+	Param localpar;
+
+protected:
+	std::pair<double, float> *funs[2];
+	SolidsShapeTypeModel *sst_models[2];
+	std::vector<double> (SimilMeasureDistribution::*distribution_fun)(int samples_taken, Model *sampled);
+
+	void fillPointsWeights(std::pair<double, float> *fun, feature_t *points, float *weights);
+	double getDistance();
+	std::vector<double> D2(int samples_taken, Model *sampled);
+	std::vector<double> D1(int samples_taken, Model *sampled);
+	std::vector<double> D3(int samples_taken, Model *sampled);
+	std::vector<double> D4(int samples_taken, Model *sampled);
+	std::vector<double> A3(int samples_taken, Model *sampled);
+};
+
+#endif /* DISTRIBUTION_MEASURE_H */
+
Index: /cpp/frams/model/similarity/measure-greedy.cpp
===================================================================
--- /cpp/frams/model/similarity/measure-greedy.cpp	(revision 1044)
+++ /cpp/frams/model/similarity/measure-greedy.cpp	(revision 1044)
@@ -0,0 +1,1487 @@
+// This file is a part of Framsticks SDK.  http://www.framsticks.com/
+// Copyright (C) 1999-2020  Maciej Komosinski and Szymon Ulatowski.
+// See LICENSE.txt for details.
+
+#include "measure-greedy.h"
+
+#define DB(x)  //define as x if you want to print debug information
+
+const int SimilMeasureGreedy::iNOFactors = 4;
+int fuzzDepth = 0; //TODO make local, but "fuzzy vertex degree" is not activated by default
+
+#define FIELDSTRUCT SimilMeasureGreedy
+
+static ParamEntry simil_greedy_paramtab[] = {
+		{ "Similarity: greedy", 1, 7, "SimilMeasureGreedy", "Evaluates morphological dissimilarity using greedy measure. More information:\nhttp://www.framsticks.com/bib/Komosinski-et-al-2001\nhttp://www.framsticks.com/bib/Komosinski-and-Kubiak-2011\nhttp://www.framsticks.com/bib/Komosinski-2016\nhttps://doi.org/10.1007/978-3-030-16692-2_8", },
+		{ "simil_parts", 0, 0, "Weight of parts count", "f 0 100 0", FIELD(m_adFactors[0]), "Differing number of parts is also handled by the 'part degree' similarity component.", },
+		{ "simil_partdeg", 0, 0, "Weight of parts' degree", "f 0 100 1", FIELD(m_adFactors[1]), "", },
+		{ "simil_neuro", 0, 0, "Weight of neurons count", "f 0 100 0.1", FIELD(m_adFactors[2]), "", },
+		{ "simil_partgeom", 0, 0, "Weight of parts' geometric distances", "f 0 100 0", FIELD(m_adFactors[3]), "", },
+		{ "simil_fixedZaxis", 0, 0, "Fix 'z' (vertical) axis?", "d 0 1 0", FIELD(fixedZaxis), "", },
+		{ "simil_weightedMDS", 0, 0, "Should weighted MDS be used?", "d 0 1 0", FIELD(wMDS), "If activated, weighted MDS with vertex (i.e., Part) degrees as weights is used for 3D alignment of body structure.", },
+		{ "evaluateDistance", 0, PARAM_DONTSAVE | PARAM_USERHIDDEN, "evaluate model dissimilarity", "p f(oGeno,oGeno)", PROCEDURE(p_evaldistance), "Calculates dissimilarity between two models created from Geno objects.", },
+		{ 0, },
+};
+
+#undef FIELDSTRUCT
+
+SimilMeasureGreedy::SimilMeasureGreedy(): localpar(simil_greedy_paramtab, this), m_iDV(0), m_iDD(0), m_iDN(0), m_dDG(0.0)
+{	
+	localpar.setDefault();
+	
+	for (int i = 0; i < 2; i++)
+	{
+		m_aDegrees[0] = nullptr;
+		m_fuzzyNeighb[0] = nullptr;
+		m_Neighbours[0] = nullptr;
+	}
+	
+	m_pMatching = nullptr;
+	tempMatching = nullptr;
+	
+	//Determines whether "fuzzy vertex degree" should be used.
+	//In preliminary experiments in 2017, "fuzzy vertex degree" turned out to be not beneficial.
+	isFuzzy = false;
+	fuzzyDepth = 10;
+	save_matching = false;
+}
+
+double SimilMeasureGreedy::distanceForTransformation()
+{
+	// now the positions are recomputed
+	computeMatching();
+
+	// teraz m_pMatching istnieje i jest pełne
+	assert(m_pMatching != NULL);
+	assert(m_pMatching->isFull() == true);
+	// wykorzystaj to dopasowanie i geometrię do obliczenia tymczasowej wartości miary
+	
+	int iTempRes = countPartsDistance();
+	// załóż sukces
+	assert(iTempRes == 1);
+	double dCurrentSim = m_adFactors[0] * double(m_iDV) +
+		m_adFactors[1] * double(m_iDD) +
+		m_adFactors[2] * double(m_iDN) +
+		m_adFactors[3] * double(m_dDG);
+	// załóż poprawną wartość podobieństwa
+	assert(dCurrentSim >= 0.0);
+	SAFEDELETE(tempMatching);
+	return dCurrentSim;
+}
+
+
+double SimilMeasureGreedy::distanceWithoutAlignment()
+{
+	return distanceForTransformation();
+}
+
+void SimilMeasureGreedy::beforeTransformation()
+{
+	if (m_pMatching != NULL)
+		if (!m_pMatching->isEmpty())
+			m_pMatching->empty();
+}
+
+/** Computes elements of similarity (m_iDD, m_iDN, m_dDG) based on underlying matching.
+	Assumptions:
+	- Matching (m_pMatching) exists and is full.
+	- Internal arrays m_aDegrees and coordinates exist and are properly filled in
+	Exit conditions:
+	- Elements of similarity are computed (m)iDD, m_iDN, m_dDG).
+	@return 1 if success, otherwise 0.
+	*/
+int SimilMeasureGreedy::countPartsDistance()
+{
+	int i, temp;
+
+	// assume existence of m_pMatching
+	assert(m_pMatching != NULL);
+	// musi byc pelne!
+	assert(m_pMatching->isFull() == true);
+
+	// roznica w stopniach
+	m_iDD = 0;
+	// roznica w liczbie neuronów
+	m_iDN = 0;
+	// roznica w odleglosci dopasowanych Parts
+	m_dDG = 0.0;
+
+	int iOrgPart, iOrgMatchedPart; // orginalny indeks Part i jego dopasowanego Part
+	int iMatchedPart; // indeks (wg sortowania) dopasowanego Part
+
+	// wykorzystanie dopasowania do zliczenia m_iDD - roznicy w stopniach
+	// i m_iDN - roznicy w liczbie neuronow
+	// petla w wiekszej tablicy
+	for (i = 0; i < m_aiPartCount[1 - m_iSmaller]; i++)
+	{
+		// dla kazdego elementu [i] z wiekszego organizmu
+		// pobierz jego orginalny indeks w organizmie z tablicy TDN
+		iOrgPart = m_aDegrees[1 - m_iSmaller][i][0];
+		if (!(m_pMatching->isMatched(1 - m_iSmaller, i)))
+		{
+			// gdy nie zostal dopasowany
+			// dodaj jego stopien do DD
+			m_iDD += m_aDegrees[1 - m_iSmaller][i][1];
+			// dodaj liczbe neuronow do DN
+			m_iDN += m_aDegrees[1 - m_iSmaller][i][3];
+			// i oblicz odleglosc tego Part od srodka organizmu (0,0,0)
+			// (uzyj orginalnego indeksu)
+			//no need to compute distane when m_dDG weight is 0
+			m_dDG += m_adFactors[3] == 0 ? 0 : coordinates[1 - m_iSmaller][iOrgPart].length();
+		}
+		else
+		{
+			// gdy byl dopasowany
+			// pobierz indeks (po sortowaniu) tego dopasowanego Part
+			iMatchedPart = m_pMatching->getMatchedIndex(1 - m_iSmaller, i);
+			// pobierz indeks orginalny tego dopasowanego Part
+			iOrgMatchedPart = m_aDegrees[m_iSmaller][iMatchedPart][0];
+			// dodaj ABS roznicy stopni do DD
+			temp = m_aDegrees[1 - m_iSmaller][i][1] -
+				m_aDegrees[m_iSmaller][iMatchedPart][1];
+			m_iDD += abs(temp);
+			// dodaj ABS roznicy neuronow do DN
+			temp = m_aDegrees[1 - m_iSmaller][i][3] -
+				m_aDegrees[m_iSmaller][iMatchedPart][3];
+			m_iDN += abs(temp);
+			// pobierz polozenie dopasowanego Part
+			Pt3D MatchedPartPos(coordinates[m_iSmaller][iOrgMatchedPart]);
+			// dodaj euklidesowa odleglosc Parts do sumy odleglosci
+			//no need to compute distane when m_dDG weight is 0
+			m_dDG += m_adFactors[3] == 0 ? 0 : coordinates[1 - m_iSmaller][iOrgPart].distanceTo(MatchedPartPos);
+		}
+	}
+
+	// obliczenie i dodanie różnicy w liczbie neuronów OnJoint...
+	temp = m_aOnJoint[0][3] - m_aOnJoint[1][3];
+	m_iDN += abs(temp);
+	DB(printf("OnJoint DN: %i\n", abs(temp));)
+		// ... i Anywhere
+		temp = m_aAnywhere[0][3] - m_aAnywhere[1][3];
+	m_iDN += abs(temp);
+	DB(printf("Anywhere DN: %i\n", abs(temp));)
+
+		return 1;
+}
+
+void SimilMeasureGreedy::computeMatching()
+{
+	// uniwersalne liczniki
+	int i, j;
+
+	assert(m_pMatching != NULL);
+	assert(m_pMatching->isEmpty() == true);
+
+	// rozpoczynamy etap dopasowywania Parts w organizmach
+	// czy dopasowano już wszystkie Parts?
+	int iCzyDopasowane = 0;
+	// koniec grupy aktualnie dopasowywanej w każdym organizmie
+	int aiKoniecGrupyDopasowania[2] = { 0, 0 };
+	// koniec grupy już w całości dopasowanej
+	// (Pomiedzy tymi dwoma indeksami znajduja sie Parts w tablicy
+	// m_aDegrees, ktore moga byc dopasowywane (tam nadal moga
+	// byc tez dopasowane - ale nie musi to byc w sposob
+	// ciagly)
+	int aiKoniecPierwszejGrupy[2] = { 0, 0 };
+	// Tablica przechowująca odległości poszczególnych Parts z aktualnych
+	// grup dopasowania. Rozmiar - prostokąt o bokach równych liczbie elementów w 
+	// dopasowywanych aktualnie grupach. Pierwszy wymiar - pierwszy organizm.
+	// Drugi wymiar - drugi organizm (nie zależy to od tego, który jest mniejszy).
+	// Wliczane w rozmiar tablicy są nawet już dopasowane elementy - tablice
+	// paiCzyDopasowany pamiętają stan dopasowania tych elementów.
+	typedef double *TPDouble;
+	double **aadOdleglosciParts;
+	// dwie tablice okreslajace Parts, ktore moga byc do siebie dopasowywane
+	// rozmiary: [0] - aiRozmiarCalychGrup[1]
+	//			 [1] - aiRozmiarCalychGrup[0]
+	std::vector<bool> *apvbCzyMinimalnaOdleglosc[2];
+	// rozmiar aktualnie dopasowywanej grupy w odpowiednim organizmie (tylko elementy
+	// jeszcze niedopasowane).
+	int aiRozmiarGrupy[2];
+	// rozmiar aktualnie dopasowywanych grup w odpowiednim organizmie (włączone są
+	// w to również elementy już dopasowane).
+	int aiRozmiarCalychGrup[2] = { 0, 0 };
+
+	// DOPASOWYWANIE PARTS
+	while (!iCzyDopasowane)
+	{
+		// znajdz konce obu grup aktualnie dopasowywanych w obu organizmach
+		for (i = 0; i < 2; i++)
+		{
+			// czyli poszukaj miejsca zmiany stopnia lub konca tablicy
+			for (j = aiKoniecPierwszejGrupy[i] + 1; j < m_aiPartCount[i]; j++)
+			{
+				if (m_aDegrees[i][j][DEG] < m_aDegrees[i][j - 1][DEG])
+				{
+					break;
+				}
+			}
+			aiKoniecGrupyDopasowania[i] = j;
+
+			// sprawdz poprawnosc tego indeksu
+			assert((aiKoniecGrupyDopasowania[i] > 0) &&
+				(aiKoniecGrupyDopasowania[i] <= m_aiPartCount[i]));
+
+			// oblicz rozmiary całych grup - łącznie z dopasowanymi już elementami
+			aiRozmiarCalychGrup[i] = aiKoniecGrupyDopasowania[i] -
+				aiKoniecPierwszejGrupy[i];
+
+			// sprawdz teraz rozmiar tej grupy w sensie liczby niedopasowanzch
+			// nie moze to byc puste!
+			aiRozmiarGrupy[i] = 0;
+			for (j = aiKoniecPierwszejGrupy[i]; j < aiKoniecGrupyDopasowania[i]; j++)
+			{
+				// od poczatku do konca grupy
+				if (!m_pMatching->isMatched(i, j))
+				{
+					// jesli niedopasowany, to zwieksz licznik
+					aiRozmiarGrupy[i]++;
+				}
+			}
+			// grupa nie moze byc pusta!
+			assert(aiRozmiarGrupy[i] > 0);
+		}
+
+		// DOPASOWYWANIE PARTS Z GRUP
+
+		// stworzenie tablicy odległości lokalnych
+		// stwórz pierwszy wymiar - wg rozmiaru zerowego organizmu
+		aadOdleglosciParts = new TPDouble[aiRozmiarCalychGrup[0]];
+		assert(aadOdleglosciParts != NULL);
+		// stwórz drugi wymiar - wg rozmiaru drugiego organizmu
+		for (i = 0; i < aiRozmiarCalychGrup[0]; i++)
+		{
+			aadOdleglosciParts[i] = new double[aiRozmiarCalychGrup[1]];
+			assert(aadOdleglosciParts[i] != NULL);
+		}
+
+		// stworzenie tablic mozliwosci dopasowania (indykatorow minimalnej odleglosci)
+		apvbCzyMinimalnaOdleglosc[0] = new std::vector<bool>(aiRozmiarCalychGrup[1], false);
+		apvbCzyMinimalnaOdleglosc[1] = new std::vector<bool>(aiRozmiarCalychGrup[0], false);
+		// sprawdz stworzenie tablic
+		assert(apvbCzyMinimalnaOdleglosc[0] != NULL);
+		assert(apvbCzyMinimalnaOdleglosc[1] != NULL);
+
+		// wypełnienie elementów macierzy (i,j) odległościami pomiędzy
+		// odpowiednimi Parts: (i) w organizmie 0 i (j) w organizmie 1.
+		// UWAGA! Uwzględniamy tylko te Parts, które nie są jeszcze dopasowane
+		// (reszta to byłaby po prostu strata czasu).
+		int iDeg, iNeu; // ilościowe określenie różnic stopnia, liczby neuronów i połączeń Parts
+		//int iNIt;
+		double dGeo; // ilościowe określenie różnic geometrycznych pomiędzy Parts
+		// indeksy konkretnych Parts - indeksy sa ZERO-BASED, choć właściwy dostep
+		// do informacji o Part wymaga dodania aiKoniecPierwszejGrupy[]
+		// tylko aadOdleglosciParts[][] indeksuje sie bezposrednio zawartoscia iIndex[]
+		int iIndex[2];
+		int iPartIndex[2] = { -1, -1 }; // at [iModel]: original index of a Part for the specified model (iModel)
+
+		// debug - wypisz zakres dopasowywanych indeksow
+		DB(printf("Organizm 0: grupa: (%2i, %2i)\n", aiKoniecPierwszejGrupy[0],
+			aiKoniecGrupyDopasowania[0]);)
+			DB(printf("Organizm 1: grupa: (%2i, %2i)\n", aiKoniecPierwszejGrupy[1],
+				aiKoniecGrupyDopasowania[1]);)
+
+			for (i = 0; i < aiRozmiarCalychGrup[0]; i++)
+			{
+
+				// iterujemy i - Parts organizmu 0
+				// (indeks podstawowy - aiKoniecPierwszejGrupy[0])
+
+				if (!(m_pMatching->isMatched(0, aiKoniecPierwszejGrupy[0] + i)))
+				{
+					// interesuja nas tylko te niedopasowane jeszcze (i)
+					for (j = 0; j < aiRozmiarCalychGrup[1]; j++)
+					{
+
+						// iterujemy j - Parts organizmu 1
+						// (indeks podstawowy - aiKoniecPierwszejGrupy[1])
+
+						if (!(m_pMatching->isMatched(1, aiKoniecPierwszejGrupy[1] + j)))
+						{
+							// interesuja nas tylko te niedopasowane jeszcze (j)
+							// teraz obliczymy lokalne różnice pomiędzy Parts
+							iDeg = abs(m_aDegrees[0][aiKoniecPierwszejGrupy[0] + i][1]
+								- m_aDegrees[1][aiKoniecPierwszejGrupy[1] + j][1]);
+
+							//iNit currently is not a component of distance measure
+							//iNIt = abs(m_aDegrees[0][ aiKoniecPierwszejGrupy[0] + i ][2]
+							//- m_aDegrees[1][ aiKoniecPierwszejGrupy[1] + j ][2]);
+
+							iNeu = abs(m_aDegrees[0][aiKoniecPierwszejGrupy[0] + i][3]
+								- m_aDegrees[1][aiKoniecPierwszejGrupy[1] + j][3]);
+
+							// obliczenie także lokalnych różnic geometrycznych pomiędzy Parts
+							// find original indices of Parts for both of the models
+							iPartIndex[0] = m_aDegrees[0][aiKoniecPierwszejGrupy[0] + i][0];
+							iPartIndex[1] = m_aDegrees[1][aiKoniecPierwszejGrupy[1] + j][0];
+							// now compute the geometrical distance of these Parts (use coordinates
+							// which should be computed by SVD)
+							Pt3D Part0Pos(coordinates[0][iPartIndex[0]]);
+							Pt3D Part1Pos(coordinates[1][iPartIndex[1]]);
+							dGeo = m_adFactors[3] == 0 ? 0 : Part0Pos.distanceTo(Part1Pos); //no need to compute distane when m_dDG weight is 0
+
+							// tutaj prawdopodobnie należy jeszcze dodać sprawdzanie
+							// identyczności pozostałych własności (oprócz geometrii)
+							// - żeby móc stwierdzić w ogóle identyczność Parts
+
+							// i ostateczna odleglosc indukowana przez te roznice
+							// (tutaj nie ma różnicy w liczbie wszystkich wierzchołków)
+							aadOdleglosciParts[i][j] = m_adFactors[1] * double(iDeg) +
+								m_adFactors[2] * double(iNeu) +
+								m_adFactors[3] * dGeo;
+							DB(printf("Parts Distance (%2i,%2i) = %.3lf\n", aiKoniecPierwszejGrupy[0] + i,
+								aiKoniecPierwszejGrupy[1] + j, aadOdleglosciParts[i][j]);)
+								DB(printf("Parts geometrical distance = %.20lf\n", dGeo);)
+								DB(printf("Pos0: (%.3lf %.3lf %.3lf)\n", Part0Pos.x, Part0Pos.y, Part0Pos.z);)
+								DB(printf("Pos1: (%.3lf %.3lf %.3lf)\n", Part1Pos.x, Part1Pos.y, Part1Pos.z);)
+						}
+					}
+				}
+			}
+
+		// tutaj - sprawdzic tylko, czy tablica odleglosci lokalnych jest poprawnie obliczona
+
+		// WYKORZYSTANIE TABLICY ODLEGLOSCI DO BUDOWY DOPASOWANIA
+
+		// trzeba raczej iterować aż do zebrania wszystkich możliwych dopasowań w grupie
+		// dlatego wprowadzamy dodatkowa zmienna - czy skonczyla sie juz grupa
+		bool bCzyKoniecGrupy = false;
+		while (!bCzyKoniecGrupy)
+		{
+			for (i = 0; i < 2; i++)
+			{
+				// iterujemy (i) po organizmach
+				// szukamy najpierw jakiegoś niedopasowanego jeszcze Part w organizmach
+
+				// zakładamy, że nie ma takiego Part
+				iIndex[i] = -1;
+
+				for (j = 0; j < aiRozmiarCalychGrup[i]; j++)
+				{
+					// iterujemy (j) - Parts organizmu (i)
+					// (indeks podstawowy - aiKoniecPierwszejGrupy[0])
+					if (!(m_pMatching->isMatched(i, aiKoniecPierwszejGrupy[i] + j)))
+					{
+						// gdy mamy w tej grupie jakis niedopasowany element, to ustawiamy
+						// iIndex[i] (chcemy w zasadzie pierwszy taki)
+						iIndex[i] = j;
+						break;
+					}
+				}
+
+				// sprawdzamy, czy w ogole znaleziono taki Part
+				if (iIndex[i] < 0)
+				{
+					// gdy nie znaleziono takiego Part - mamy koniec dopasowywania w
+					// tych grupach
+					bCzyKoniecGrupy = true;
+				}
+				// sprawdz poprawnosc indeksu niedopasowanego Part - musi byc w aktualnej grupie
+				assert((iIndex[i] >= -1) && (iIndex[i] < aiRozmiarCalychGrup[i]));
+			}
+
+
+			// teraz mamy sytuacje:
+			// - mamy w iIndex[0] i iIndex[1] indeksy pierwszych niedopasowanych Part
+			//		w organizmach, albo
+			// - nie ma w ogóle już czego dopasowywać (należy przejść do innej grupy)
+			if (!bCzyKoniecGrupy)
+			{
+				// gdy nie ma jeszcze końca żadnej z grup - możemy dopasowywać
+				// najpierw wyszukujemy w tablicy minimum odległości od tych
+				// wyznaczonych Parts
+
+				// najpierw wyczyscimy wektory potencjalnych dopasowan
+				// dla organizmu 1 (o rozmiarze grupy z 0)
+				for (i = 0; i < aiRozmiarCalychGrup[0]; i++)
+				{
+					apvbCzyMinimalnaOdleglosc[1]->operator[](i) = false;
+				}
+				// dla organizmu 0 (o rozmiarze grup z 1)
+				for (i = 0; i < aiRozmiarCalychGrup[1]; i++)
+				{
+					apvbCzyMinimalnaOdleglosc[0]->operator[](i) = false;
+				}
+
+				// szukanie minimum dla Part o indeksie iIndex[0] w organizmie 0
+				// wsrod niedopasowanych Parts z organizmu 1
+				// zakładamy, że nie znaleliśmy jeszcze minimum
+				double dMinimum = HUGE_VAL;
+				for (i = 0; i < aiRozmiarCalychGrup[1]; i++)
+				{
+					if (!(m_pMatching->isMatched(1, aiKoniecPierwszejGrupy[1] + i)))
+					{
+
+						// szukamy minimum obliczonej lokalnej odleglosci tylko wsrod
+						// niedopasowanych jeszcze Parts
+						if (aadOdleglosciParts[iIndex[0]][i] < dMinimum)
+						{
+							dMinimum = aadOdleglosciParts[iIndex[0]][i];
+						}
+						// przy okazji - sprawdz, czy HUGE_VAL jest rzeczywiscie max dla double
+						assert(aadOdleglosciParts[iIndex[0]][i] < HUGE_VAL);
+					}
+				}
+				// sprawdz, czy minimum znaleziono - musi takie byc, bo jest cos niedopasowanego
+				assert((dMinimum >= 0.0) && (dMinimum < HUGE_VAL));
+
+				// teraz zaznaczamy w tablicy te wszystkie Parts, ktore maja
+				// rzeczywiscie te minimalna odleglosc do Part iIndex[0] w organizmie 0
+				for (i = 0; i < aiRozmiarCalychGrup[1]; i++)
+				{
+					if (!(m_pMatching->isMatched(1, aiKoniecPierwszejGrupy[1] + i)))
+					{
+						if (aadOdleglosciParts[iIndex[0]][i] == dMinimum)
+						{
+							// jesli w danym miejscu tablicy odleglosci jest faktyczne
+							// minimum odleglosci, to mamy potencjalna pare dla iIndex[0]
+							apvbCzyMinimalnaOdleglosc[0]->operator[](i) = true;
+						}
+
+						// sprawdz poprawnosc znalezionego wczesniej minimum
+						assert(aadOdleglosciParts[iIndex[0]][i] >= dMinimum);
+					}
+				}
+
+				// podobnie szukamy minimum dla Part o indeksie iIndex[1] w organizmie 1
+				// wsrod niedopasowanych Parts z organizmu 0
+				dMinimum = HUGE_VAL;
+				for (i = 0; i < aiRozmiarCalychGrup[0]; i++)
+				{
+					if (!(m_pMatching->isMatched(0, aiKoniecPierwszejGrupy[0] + i)))
+					{
+						// szukamy minimum obliczonej lokalnej odleglosci tylko wsrod
+						// niedopasowanych jeszcze Parts
+						if (aadOdleglosciParts[i][iIndex[1]] < dMinimum)
+						{
+							dMinimum = aadOdleglosciParts[i][iIndex[1]];
+						}
+						// przy okazji - sprawdz, czy HUGE_VAL jest rzeczywiscie max dla double
+						assert(aadOdleglosciParts[i][iIndex[1]] < HUGE_VAL);
+					}
+				}
+				// sprawdz, czy minimum znaleziono - musi takie byc, bo jest cos niedopasowanego
+				assert((dMinimum >= 0.0) && (dMinimum < HUGE_VAL));
+
+				// teraz zaznaczamy w tablicy te wszystkie Parts, ktore maja
+				// rzeczywiscie te minimalne odleglosci do Part iIndex[1] w organizmie 1
+				for (i = 0; i < aiRozmiarCalychGrup[0]; i++)
+				{
+					if (!(m_pMatching->isMatched(0, aiKoniecPierwszejGrupy[0] + i)))
+					{
+						if (aadOdleglosciParts[i][iIndex[1]] == dMinimum)
+						{
+							// jesli w danym miejscu tablicy odleglosci jest faktyczne
+							// minimum odleglosci, to mamy potencjalna pare dla iIndex[1]
+							apvbCzyMinimalnaOdleglosc[1]->operator[](i) = true;
+						}
+
+						// sprawdz poprawnosc znalezionego wczesniej minimum
+						assert(aadOdleglosciParts[i][iIndex[1]] >= dMinimum);
+					}
+				}
+
+				// teraz mamy juz poszukane potencjalne grupy dopasowania - musimy
+				// zdecydowac, co do czego dopasujemy!
+				// szukamy Part iIndex[0] posrod mozliwych do dopasowania dla Part iIndex[1]
+				// szukamy takze Part iIndex[1] posrod mozliwych do dopasowania dla Part iIndex[0]
+				bool PartZ1NaLiscie0 = apvbCzyMinimalnaOdleglosc[0]->operator[](iIndex[1]);
+				bool PartZ0NaLiscie1 = apvbCzyMinimalnaOdleglosc[1]->operator[](iIndex[0]);
+
+				if (PartZ1NaLiscie0 && PartZ0NaLiscie1)
+				{
+					// PRZYPADEK 1. Oba Parts maja sie wzajemnie na listach mozliwych
+					// dopasowan.
+					// AKCJA. Dopasowanie wzajemne do siebie.
+
+					m_pMatching->match(0, aiKoniecPierwszejGrupy[0] + iIndex[0],
+						1, aiKoniecPierwszejGrupy[1] + iIndex[1]);
+
+					// zmniejsz liczby niedopasowanych elementow w grupach
+					aiRozmiarGrupy[0]--;
+					aiRozmiarGrupy[1]--;
+					// debug - co zostalo dopasowane
+					DB(printf("Przypadek 1.: dopasowane Parts: (%2i, %2i)\n", aiKoniecPierwszejGrupy[0]
+						+ iIndex[0], aiKoniecPierwszejGrupy[1] + iIndex[1]);)
+
+				}// PRZYPADEK 1.
+				else
+					if (PartZ1NaLiscie0 || PartZ0NaLiscie1)
+					{
+						// PRZYPADEK 2. Tylko jeden z Parts ma drugiego na swojej liscie
+						// mozliwych dopasowan
+						// AKCJA. Dopasowanie jednego jest proste (tego, ktory nie ma 
+						// na swojej liscie drugiego). Dla tego drugiego nalezy powtorzyc
+						// duza czesc obliczen (znalezc mu nowa mozliwa pare)
+
+						// indeks organizmu, ktorego Part nie ma dopasowywanego Part
+						// z drugiego organizmu na swojej liscie
+						int iBezDrugiego;
+
+						// okreslenie indeksu organizmu z dopasowywanym Part
+						if (!PartZ1NaLiscie0)
+						{
+							iBezDrugiego = 0;
+						}
+						else
+						{
+							iBezDrugiego = 1;
+						}
+						// sprawdz indeks organizmu
+						assert((iBezDrugiego == 0) || (iBezDrugiego == 1));
+
+						int iDopasowywany = -1;
+						// poszukujemy pierwszego z listy dopasowania
+						for (i = 0; i < aiRozmiarCalychGrup[1 - iBezDrugiego]; i++)
+						{
+							if (apvbCzyMinimalnaOdleglosc[iBezDrugiego]->operator[](i))
+							{
+								iDopasowywany = i;
+								break;
+							}
+						}
+						// sprawdz poprawnosc indeksu dopasowywanego (musimy cos znalezc!)
+						// nieujemny i w odpowiedniej grupie!
+						assert((iDopasowywany >= 0) &&
+							(iDopasowywany < aiRozmiarCalychGrup[1 - iBezDrugiego]));
+
+						// znalezlismy 1. Part z listy dopasowania - dopasowujemy!
+						m_pMatching->match(
+							iBezDrugiego,
+							aiKoniecPierwszejGrupy[iBezDrugiego] + iIndex[iBezDrugiego],
+							1 - iBezDrugiego,
+							aiKoniecPierwszejGrupy[1 - iBezDrugiego] + iDopasowywany);
+						DB(printf("Przypadek 2.1.: dopasowane Parts dopasowanie bez drugiego: (%2i, %2i)\n", aiKoniecPierwszejGrupy[iBezDrugiego] + iIndex[iBezDrugiego],
+							aiKoniecPierwszejGrupy[1 - iBezDrugiego] + iDopasowywany);)
+
+							// zmniejsz liczby niedopasowanych elementow w grupach
+							aiRozmiarGrupy[0]--;
+						aiRozmiarGrupy[1]--;
+
+						// sprawdz, czy jest szansa dopasowania tego Part z drugiej strony
+						// (ktora miala mozliwosc dopasowania tego Part z poprzedniego organizmu)
+						if ((aiRozmiarGrupy[0] > 0) && (aiRozmiarGrupy[1] > 0))
+						{
+							// jesli grupy sie jeszcze nie wyczrpaly
+							// to jest mozliwosc dopasowania w organizmie
+
+							int iZDrugim = 1 - iBezDrugiego;
+							// sprawdz indeks organizmu
+							assert((iZDrugim == 0) || (iZDrugim == 1));
+
+							// bedziemy szukac minimum wsrod niedopasowanych - musimy wykasowac
+							// poprzednie obliczenia minimum
+							// dla organizmu 1 (o rozmiarze grupy z 0)
+							for (i = 0; i < aiRozmiarCalychGrup[0]; i++)
+							{
+								apvbCzyMinimalnaOdleglosc[1]->operator[](i) = false;
+							}
+							// dla organizmu 0 (o rozmiarze grup z 1)
+							for (i = 0; i < aiRozmiarCalychGrup[1]; i++)
+							{
+								apvbCzyMinimalnaOdleglosc[0]->operator[](i) = false;
+							}
+
+							// szukamy na nowo minimum dla Part o indeksie iIndex[ iZDrugim ] w organizmie iZDrugim
+							// wsrod niedopasowanych Parts z organizmu 1 - iZDrugim
+							dMinimum = HUGE_VAL;
+							for (i = 0; i < aiRozmiarCalychGrup[1 - iZDrugim]; i++)
+							{
+								if (!(m_pMatching->isMatched(
+									1 - iZDrugim,
+									aiKoniecPierwszejGrupy[1 - iZDrugim] + i)))
+								{
+									// szukamy minimum obliczonej lokalnej odleglosci tylko wsrod
+									// niedopasowanych jeszcze Parts
+									if (iZDrugim == 0)
+									{
+										// teraz niestety musimy rozpoznac odpowiedni organizm
+										// zeby moc indeksowac niesymetryczna tablice
+										if (aadOdleglosciParts[iIndex[0]][i] < dMinimum)
+										{
+											dMinimum = aadOdleglosciParts[iIndex[0]][i];
+										}
+										// przy okazji - sprawdz, czy HUGE_VAL jest rzeczywiscie max dla double
+										assert(aadOdleglosciParts[iIndex[0]][i] < HUGE_VAL);
+
+									}
+									else
+									{
+										if (aadOdleglosciParts[i][iIndex[1]] < dMinimum)
+										{
+											dMinimum = aadOdleglosciParts[i][iIndex[1]];
+										}
+										// przy okazji - sprawdz, czy HUGE_VAL jest rzeczywiscie max dla double
+										assert(aadOdleglosciParts[i][iIndex[1]] < HUGE_VAL);
+									}
+								}
+							}
+							// sprawdz, czy minimum znaleziono - musi takie byc, bo jest cos niedopasowanego
+							assert((dMinimum >= 0.0) && (dMinimum < HUGE_VAL));
+
+							// teraz zaznaczamy w tablicy te wszystkie Parts, ktore maja
+							// rzeczywiscie te minimalne odleglosci do Part w organizmie iZDrugim
+							for (i = 0; i < aiRozmiarCalychGrup[1 - iZDrugim]; i++)
+							{
+								if (!(m_pMatching->isMatched(
+									1 - iZDrugim,
+									aiKoniecPierwszejGrupy[1 - iZDrugim] + i)))
+								{
+									if (iZDrugim == 0)
+									{
+										// teraz niestety musimy rozpoznac odpowiedni organizm
+										// zeby moc indeksowac niesymetryczna tablice
+										if (aadOdleglosciParts[iIndex[0]][i] == dMinimum)
+										{
+											// jesli w danym miejscu tablicy odleglosci jest faktyczne 
+											// minimum odleglosci, to mamy potencjalna pare dla iIndex[1]
+											apvbCzyMinimalnaOdleglosc[0]->operator[](i) = true;
+										}
+									}
+									else
+									{
+										if (aadOdleglosciParts[i][iIndex[1]] == dMinimum)
+										{
+											apvbCzyMinimalnaOdleglosc[1]->operator[](i) = true;
+										}
+									}
+								}
+							}
+
+							// a teraz - po znalezieniu potencjalnych elementow do dopasowania
+							// dopasowujemy pierwszy z potencjalnych
+							iDopasowywany = -1;
+							for (i = 0; i < aiRozmiarCalychGrup[1 - iZDrugim]; i++)
+							{
+								if (apvbCzyMinimalnaOdleglosc[iZDrugim]->operator[](i))
+								{
+									iDopasowywany = i;
+									break;
+								}
+							}
+							// musielismy znalezc jakiegos dopasowywanego
+							assert((iDopasowywany >= 0) &&
+								(iDopasowywany < aiRozmiarCalychGrup[1 - iZDrugim]));
+
+							// no to juz mozemy dopasowac
+							m_pMatching->match(
+								iZDrugim,
+								aiKoniecPierwszejGrupy[iZDrugim] + iIndex[iZDrugim],
+								1 - iZDrugim,
+								aiKoniecPierwszejGrupy[1 - iZDrugim] + iDopasowywany);
+							DB(printf("Przypadek 2.1.: dopasowane Parts dopasowaniebz drugim: (%2i, %2i)\n", aiKoniecPierwszejGrupy[iZDrugim] + iIndex[iZDrugim], aiKoniecPierwszejGrupy[1 - iZDrugim] + iDopasowywany);)
+
+								//aiKoniecPierwszejGrupy[ 1-iBezDrugiego ] + iDopasowywany ;)
+								//aiKoniecPierwszejGrupy[ 1-iBezDrugiego ] + iDopasowywany ;)
+								// zmniejsz liczby niedopasowanych elementow w grupach
+								aiRozmiarGrupy[0]--;
+							aiRozmiarGrupy[1]--;
+
+						}
+						else
+						{
+							// jedna z grup sie juz wyczerpala
+							// wiec nie ma mozliwosci dopasowania tego drugiego Partu
+							/// i trzeba poczekac na zmiane grupy
+						}
+
+						DB(printf("Przypadek 2.\n");)
+
+					}// PRZYPADEK 2.
+					else
+					{
+						// PRZYPADEK 3. Zaden z Parts nie ma na liscie drugiego
+						// AKCJA. Niezalezne dopasowanie obu Parts do pierwszych ze swojej listy
+
+						// najpierw dopasujemy do iIndex[0] w organizmie 0
+						int iDopasowywany = -1;
+						// poszukujemy pierwszego z listy dopasowania - w organizmie 1
+						for (i = 0; i < aiRozmiarCalychGrup[1]; i++)
+						{
+							if (apvbCzyMinimalnaOdleglosc[0]->operator[](i))
+							{
+								iDopasowywany = i;
+								break;
+							}
+						}
+						// musielismy znalezc jakiegos dopasowywanego
+						assert((iDopasowywany >= 0) &&
+							(iDopasowywany < aiRozmiarCalychGrup[1]));
+
+						// teraz wlasnie dopasowujemy
+						m_pMatching->match(
+							0,
+							aiKoniecPierwszejGrupy[0] + iIndex[0],
+							1,
+							aiKoniecPierwszejGrupy[1] + iDopasowywany);
+
+						// zmniejszamy liczbe niedopasowanych Parts
+						aiRozmiarGrupy[0]--;
+						aiRozmiarGrupy[1]--;
+
+						// debug - dopasowanie
+						DB(printf("Przypadek 3.: dopasowane Parts: (%2i, %2i)\n", aiKoniecPierwszejGrupy[0]
+							+ iIndex[0], aiKoniecPierwszejGrupy[1] + iDopasowywany);)
+
+							// teraz dopasowujemy do iIndex[1] w organizmie 1
+							iDopasowywany = -1;
+						// poszukujemy pierwszego z listy dopasowania - w organizmie 0
+						for (i = 0; i < aiRozmiarCalychGrup[0]; i++)
+						{
+							if (apvbCzyMinimalnaOdleglosc[1]->operator[](i))
+							{
+								iDopasowywany = i;
+								break;
+							}
+						}
+						// musielismy znalezc jakiegos dopasowywanego
+						assert((iDopasowywany >= 0) &&
+							(iDopasowywany < aiRozmiarCalychGrup[0]));
+
+						// no i teraz realizujemy dopasowanie
+						m_pMatching->match(
+							0,
+							aiKoniecPierwszejGrupy[0] + iDopasowywany,
+							1,
+							aiKoniecPierwszejGrupy[1] + iIndex[1]);
+
+						// zmniejszamy liczbe niedopasowanych Parts
+						aiRozmiarGrupy[0]--;
+						aiRozmiarGrupy[1]--;
+
+						// debug - dopasowanie
+						DB(printf("Przypadek 3.: dopasowane Parts: (%2i, %2i)\n", aiKoniecPierwszejGrupy[0]
+							+ iDopasowywany, aiKoniecPierwszejGrupy[1] + iIndex[1]);)
+
+
+					} // PRZYPADEK 3.
+
+			}// if (! bCzyKoniecGrupy)
+			else
+			{
+				// gdy mamy juz koniec grup - musimy zlikwidowac tablice aadOdleglosciParts
+				// bo za chwilke skonczy sie nam petla
+				for (i = 0; i < aiRozmiarCalychGrup[0]; i++)
+				{
+					SAFEDELETEARRAY(aadOdleglosciParts[i]);
+				}
+				SAFEDELETEARRAY(aadOdleglosciParts);
+
+				// musimy tez usunac tablice (wektory) mozliwosci dopasowania
+				SAFEDELETE(apvbCzyMinimalnaOdleglosc[0]);
+				SAFEDELETE(apvbCzyMinimalnaOdleglosc[1]);
+			}
+		} // while (! bCzyKoniecGrupy)
+
+		// PO DOPASOWANIU WSZYSTKIEGO Z GRUP (CO NAJMNIEJ JEDNEJ GRUPY W CALOSCI)
+
+		// gdy rozmiar ktorejkolwiek z grup dopasowania spadl do zera
+		// to musimy przesunac KoniecPierwszejGrupy (wszystkie dopasowane)
+		for (i = 0; i < 2; i++)
+		{
+			// grupy nie moga miec mniejszego niz 0 rozmiaru
+			assert(aiRozmiarGrupy[i] >= 0);
+			if (aiRozmiarGrupy[i] == 0)
+				aiKoniecPierwszejGrupy[i] = aiKoniecGrupyDopasowania[i];
+		}
+
+		// sprawdzenie warunku konca dopasowywania - gdy nie
+		// ma juz w jakims organizmie co dopasowywac
+		if (aiKoniecPierwszejGrupy[0] >= m_aiPartCount[0] ||
+			aiKoniecPierwszejGrupy[1] >= m_aiPartCount[1])
+		{
+			iCzyDopasowane = 1;
+		}
+	} // koniec WHILE - petli dopasowania
+}
+
+void SimilMeasureGreedy::copyMatching()
+{
+	SAFEDELETE(tempMatching);
+	tempMatching = new SimilMatching(*m_pMatching);
+}
+
+void SimilMeasureGreedy::prepareData()
+{	
+	// create Parts matching object
+	m_pMatching = new SimilMatching(models[0]->getPartCount(), models[1]->getPartCount());
+
+	// utworzenie tablicy rozmiarow
+	for (int i = 0; i < 2; i++)
+	{
+		m_aiPartCount[i] = models[i]->getPartCount();
+	}
+	
+	// difference in the number of vertices (Parts) - positive
+	// find object that has less parts (m_iSmaller)
+	m_iDV = (models[0]->getPartCount() - models[1]->getPartCount());
+	if (m_iDV < 0)
+		m_iDV = -m_iDV;
+
+	// check if index of the smaller organism is a valid index
+	assert((m_iSmaller == 0) || (m_iSmaller == 1));
+	// validate difference in the parts number
+	assert(m_iDV >= 0);
+	
+	if (!createPartInfoTables())
+		logPrintf("GreedyMeasure", "PrepareData", LOG_ERROR, "Unable to create part info tables.");
+	if (!countPartDegrees())
+		logPrintf("GreedyMeasure", "PrepareData", LOG_ERROR, "Unable to count part degrees.");
+	if (!countPartNeurons())
+		logPrintf("GreedyMeasure", "PrepareData", LOG_ERROR, "Unable to count part neurons.");
+
+	DB(printf("Przed sortowaniem:\n");)
+	DB(_PrintDegrees(0);)
+	DB(_PrintDegrees(1);)
+
+	if (!sortPartInfoTables())
+		logPrintf("GreedyMeasure", "PrepareData", LOG_ERROR, "Unable to sort part info tables.");
+
+	DB(printf("Po sortowaniu:\n");)
+	DB(_PrintDegrees(0);)
+	DB(_PrintDegrees(1);)
+}
+
+void SimilMeasureGreedy::cleanData()
+{
+	// delete degree arrays created in CreatePartInfoTables 
+	SAFEDELETEARRAY(m_aDegrees[0]);
+	SAFEDELETEARRAY(m_aDegrees[1]);
+	
+	// in fuzzy mode delete arrays of neighbourhood and fuzzy neighbourhood
+	if (isFuzzy)
+	{
+		for (int i = 0; i != 2; ++i)
+		{
+			for (int j = 0; j != models[i]->getPartCount(); ++j)
+			{
+				delete[] m_Neighbours[i][j];
+				delete[] m_fuzzyNeighb[i][j];
+			}
+			delete[] m_Neighbours[i];
+			delete[] m_fuzzyNeighb[i];
+		}
+
+	}
+	
+	// delete created matching
+	SAFEDELETE(m_pMatching);
+	
+}
+
+/** Creates arrays holding information about organisms' Parts (m_aDegrees) andm_Neigh
+	fills them with initial data (original indices and zeros).
+	Assumptions:
+	- Models (models) are created and available.
+	*/
+int SimilMeasureGreedy::createPartInfoTables()
+{
+	int i, j, partCount;
+	// utwórz tablice na informacje o stopniach wierzchołków i liczbie neuroitems
+	for (i = 0; i < 2; i++)
+	{
+		partCount = models[i]->getPartCount();
+		// utworz i wypelnij tablice dla Parts wartosciami poczatkowymi
+		m_aDegrees[i] = new TDN[partCount];
+
+		if (isFuzzy)
+		{
+			m_Neighbours[i] = new int*[partCount];
+			m_fuzzyNeighb[i] = new float*[partCount];
+		}
+
+		if (m_aDegrees[i] != NULL && ((!isFuzzy) || (m_Neighbours[i] != NULL && m_fuzzyNeighb[i] != NULL)))
+		{
+			// wypelnij tablice zgodnie z sensem TDN[0] - orginalny index
+			// TDN[1], TDN[2], TDN[3] - zerami
+			DB(printf("m_aDegrees[%i]: %p\n", i, m_aDegrees[i]);)
+				for (j = 0; j < partCount; j++)
+				{
+					m_aDegrees[i][j][0] = j;
+					m_aDegrees[i][j][1] = 0;
+					m_aDegrees[i][j][2] = 0;
+					m_aDegrees[i][j][3] = 0;
+					m_aDegrees[i][j][4] = 0;
+
+					// sprawdz, czy nie piszemy po jakims szalonym miejscu pamieci
+					assert(m_aDegrees[i][j] != NULL);
+
+					if (isFuzzy)
+					{
+						m_Neighbours[i][j] = new int[partCount];
+						for (int k = 0; k < partCount; k++)
+						{
+							m_Neighbours[i][j][k] = 0;
+						}
+
+						m_fuzzyNeighb[i][j] = new float[fuzzyDepth];
+						for (int k = 0; k < fuzzyDepth; k++)
+						{
+							m_fuzzyNeighb[i][j][k] = 0;
+						}
+
+						assert(m_Neighbours[i][j] != NULL);
+						assert(m_fuzzyNeighb[i][j] != NULL);
+					}
+
+				}
+		}
+		else
+		{
+			logPrintf("ModelSimil", "CreatePartInfoTables", LOG_ERROR, "Not enough memory?");
+			return 0;
+		}
+		// wypelnij tablice OnJoints i Anywhere wartościami początkowymi
+		// OnJoint
+		m_aOnJoint[i][0] = 0;
+		m_aOnJoint[i][1] = 0;
+		m_aOnJoint[i][2] = 0;
+		m_aOnJoint[i][3] = 0;
+		// Anywhere
+		m_aAnywhere[i][0] = 0;
+		m_aAnywhere[i][1] = 0;
+		m_aAnywhere[i][2] = 0;
+		m_aAnywhere[i][3] = 0;
+	}
+	return 1;
+}
+
+/** Computes degrees of Parts of both organisms. Fills in the m_aDegrees arrays
+	with proper information about degrees.
+	Assumptions:
+	- Models (models) are created and available.
+	- Arrays m_aDegrees are created.
+	*/
+int SimilMeasureGreedy::countPartDegrees()
+{
+	Part *P1, *P2;
+	int i, j, i1, i2;
+
+	// dla obu stworzen oblicz stopnie wierzcholkow
+	for (i = 0; i < 2; i++)
+	{
+		// dla wszystkich jointow
+		for (j = 0; j < models[i]->getJointCount(); j++)
+		{
+			// pobierz kolejny Joint
+			Joint *J = models[i]->getJoint(j);
+			// wez jego konce
+			P1 = J->part1;
+			P2 = J->part2;
+			// znajdz ich indeksy w Modelu (indeksy orginalne)
+			i1 = models[i]->findPart(P1);
+			i2 = models[i]->findPart(P2);
+			// zwieksz stopien odpowiednich Parts
+			m_aDegrees[i][i1][DEG]++;
+			m_aDegrees[i][i2][DEG]++;
+			m_aDegrees[i][i1][FUZ_DEG]++;
+			m_aDegrees[i][i2][FUZ_DEG]++;
+			if (isFuzzy)
+			{
+				m_Neighbours[i][i1][i2] = 1;
+				m_Neighbours[i][i2][i1] = 1;
+			}
+		}
+		// dla elementow nie osadzonych na Parts (OnJoint, Anywhere) -
+		// stopnie wierzchołka są już ustalone na zero
+	}
+
+	if (isFuzzy)
+	{
+		countFuzzyNeighb();
+	}
+
+	return 1;
+}
+
+void SimilMeasureGreedy::getNeighbIndexes(int mod, int partInd, std::vector<int> &indexes)
+{
+	indexes.clear();
+	int i, size = models[mod]->getPartCount();
+
+	for (i = 0; i < size; i++)
+	{
+		if (m_Neighbours[mod][partInd][i] > 0)
+		{
+			indexes.push_back(i);
+		}
+	}
+}
+
+int compareFuzzyRows(const void *pa, const void *pb)
+{
+	float **a = (float**)pa;
+	float **b = (float**)pb;
+
+	for (int i = 1; i < fuzzDepth; i++)
+	{
+		if (a[0][i] > b[0][i])
+		{
+			return -1;
+		}
+		if (a[0][i] < b[0][i])
+		{
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+void SimilMeasureGreedy::fuzzyOrder()
+{
+	int i, depth, partInd, prevPartInd, partCount;
+	for (int mod = 0; mod < 2; mod++)
+	{
+		partCount = models[mod]->getPartCount();
+		partInd = m_fuzzyNeighb[mod][partCount - 1][0];
+		m_aDegrees[mod][partInd][FUZ_DEG] = 0;
+
+		for (i = (partCount - 2); i >= 0; i--)
+		{
+			prevPartInd = partInd;
+			partInd = m_fuzzyNeighb[mod][i][0];
+			m_aDegrees[mod][partInd][FUZ_DEG] = m_aDegrees[mod][prevPartInd][FUZ_DEG];
+			for (depth = 1; depth < fuzzyDepth; depth++)
+			{
+				if (m_fuzzyNeighb[mod][i][depth] != m_fuzzyNeighb[mod][i + 1][depth])
+				{
+					m_aDegrees[mod][partInd][FUZ_DEG]++;
+					break;
+				}
+			}
+		}
+	}
+}
+
+//sort according to fuzzy degree
+void SimilMeasureGreedy::sortFuzzyNeighb()
+{
+	fuzzDepth = fuzzyDepth;
+	for (int mod = 0; mod < 2; mod++)
+	{
+		std::qsort(m_fuzzyNeighb[mod], (size_t)models[mod]->getPartCount(), sizeof(m_fuzzyNeighb[mod][0]), compareFuzzyRows);
+	}
+}
+
+//computes fuzzy vertex degree
+void SimilMeasureGreedy::countFuzzyNeighb()
+{
+	std::vector<int> nIndexes;
+	float newDeg = 0;
+
+	for (int mod = 0; mod < 2; mod++)
+	{
+		int partCount = models[mod]->getPartCount();
+
+		for (int depth = 0; depth < fuzzyDepth; depth++)
+		{
+			//use first column for storing indices
+			for (int partInd = 0; partInd < partCount; partInd++)
+			{
+				if (depth == 0)
+				{
+					m_fuzzyNeighb[mod][partInd][depth] = partInd;
+				}
+				else if (depth == 1)
+				{
+					m_fuzzyNeighb[mod][partInd][depth] = m_aDegrees[mod][partInd][DEG];
+				}
+				else
+				{
+					getNeighbIndexes(mod, partInd, nIndexes);
+					for (unsigned int k = 0; k < nIndexes.size(); k++)
+					{
+						newDeg += m_fuzzyNeighb[mod][nIndexes.at(k)][depth - 1];
+					}
+					newDeg /= nIndexes.size();
+					m_fuzzyNeighb[mod][partInd][depth] = newDeg;
+					for (int mod = 0; mod < 2; mod++)
+					{
+						int partCount = models[mod]->getPartCount();
+						for (int i = partCount - 1; i >= 0; i--)
+						{
+
+						}
+					}
+					newDeg = 0;
+				}
+			}
+		}
+	}
+
+	sortFuzzyNeighb();
+	fuzzyOrder();
+}
+
+/** Computes numbers of neurons and neurons' inputs for each Part of each
+	organisms and fills in the m_aDegrees array.
+	Assumptions:
+	- Models (models) are created and available.
+	- Arrays m_aDegrees are created.
+	*/
+int SimilMeasureGreedy::countPartNeurons()
+{
+	// sprawdz zalozenie - o modelach
+	assert((models[0] != NULL) && (models[1] != NULL));
+	assert(models[0]->isValid() && models[1]->isValid());
+
+	// sprawdz zalozenie - o tablicach
+	assert(m_aDegrees[0] != NULL);
+	assert(m_aDegrees[1] != NULL);
+	
+	Part *P1;
+	Joint *J1;
+	int i, j, i2, neuro_connections;
+
+	// dla obu stworzen oblicz liczbe Neurons + connections dla Parts
+	// a takze dla OnJoints i Anywhere
+	for (i = 0; i < 2; i++)
+	{
+		for (j = 0; j < models[i]->getNeuroCount(); j++)
+		{
+			// pobierz kolejny Neuron
+			Neuro *N = models[i]->getNeuro(j);
+			// policz liczbe jego wejść i jego samego tez
+			// czy warto w ogole liczyc polaczenia...? co to da/spowoduje?
+			neuro_connections = N->getInputCount() + 1;
+			// wez Part, na ktorym jest Neuron
+			P1 = N->getPart();
+			if (P1)
+			{
+				// dla neuronow osadzonych na Partach
+				i2 = models[i]->findPart(P1); // znajdz indeks Part w Modelu
+				m_aDegrees[i][i2][2] += neuro_connections; // zwieksz liczbe Connections+Neurons dla tego Part (TDN[2])
+				m_aDegrees[i][i2][3]++; // zwieksz liczbe Neurons dla tego Part (TDN[3])
+			}
+			else
+			{
+				// dla neuronow nie osadzonych na partach
+				J1 = N->getJoint();
+				if (J1)
+				{
+					// dla tych na Jointach
+					m_aOnJoint[i][2] += neuro_connections; // zwieksz liczbe Connections+Neurons
+					m_aOnJoint[i][3]++; // zwieksz liczbe Neurons
+				}
+				else
+				{
+					// dla tych "gdziekolwiek"
+					m_aAnywhere[i][2] += neuro_connections; // zwieksz liczbe Connections+Neurons
+					m_aAnywhere[i][3]++; // zwieksz liczbe Neurons
+				}
+			}
+		}
+	}
+	return 1;
+}
+
+/** Sorts arrays m_aDegrees (for each organism) by Part's degree, and then by
+	number of neural connections and neurons in groups of Parts with the same
+	degree.
+	Assumptions:
+	- Models (models) are created and available.
+	- Arrays m_aDegrees are created.
+	@saeDegrees, CompareItemNo
+	*/
+int SimilMeasureGreedy::sortPartInfoTables()
+{
+	int i;
+	int(*pfDegreeFunction) (const void*, const void*) = NULL;
+	pfDegreeFunction = isFuzzy ? &compareFuzzyDegrees : &compareDegrees;
+	// sortowanie obu tablic wg stopni punktów - TDN[1]
+	for (i = 0; i < 2; i++)
+	{
+		DB(_PrintDegrees(i));
+		std::qsort(m_aDegrees[i], (size_t)(models[i]->getPartCount()),
+			sizeof(TDN), pfDegreeFunction);
+		DB(_PrintDegrees(i));
+	}
+
+	// sprawdzenie wartosci parametru
+	DB(i = sizeof(TDN);)
+		int degreeType = isFuzzy ? FUZ_DEG : DEG;
+
+	// sortowanie obu tablic m_aDegrees wedlug liczby neuronów i
+	// czesci neuronu - ale w obrebie grup o tym samym stopniu
+	for (i = 0; i < 2; i++)
+	{
+		int iPocz = 0;
+		int iDeg, iNewDeg, iPartCount, j;
+		// stopien pierwszego punktu w tablicy Degrees  odniesienie
+		iDeg = m_aDegrees[i][0][degreeType];
+		iPartCount = models[i]->getPartCount();
+		// po kolei dla kazdego punktu w organizmie
+		for (j = 0; j <= iPartCount; j++)
+		{
+			// sprawdz stopien punktu (lub nadaj 0 - gdy juz koniec tablicy)
+			//			iNewDeg = (j != iPartCount) ? m_aDegrees[i][j][1] : 0;
+			// usunieto stara wersje porownania!!! wprowadzono znak porownania <
+
+			iNewDeg = (j < iPartCount) ? m_aDegrees[i][j][degreeType] : 0;
+			// skoro tablice sa posortowane wg stopni, to mamy na pewno taka kolejnosc
+			assert(iNewDeg <= iDeg);
+			if (iNewDeg != iDeg)
+			{
+				// gdy znaleziono koniec grupy o tym samym stopniu
+				// sortuj po liczbie neuronow w obrebie grupy
+				DB(_PrintDegrees(i));
+				DB(printf("qsort( poczatek=%i, rozmiar=%i, sizeof(TDN)=%i)\n", iPocz, (j - iPocz), sizeof(TDN));)
+					// wyswietlamy z jedna komorka po zakonczeniu tablicy
+					DB(_PrintArray(m_aDegrees[i][iPocz], 0, (j - iPocz) * 4);)
+
+					std::qsort(m_aDegrees[i][iPocz], (size_t)(j - iPocz),
+						sizeof(TDN), SimilMeasureGreedy::compareConnsNo);
+				DB(_PrintDegrees(i));
+				// wyswietlamy z jedna komorka po zakonczeniu tablicy
+				DB(_PrintArray(m_aDegrees[i][iPocz], 0, (j - iPocz) * 4);)
+					// rozpocznij nowa grupe
+					iPocz = j;
+				iDeg = iNewDeg;
+			}
+		}
+	}
+	return 1;
+}
+
+
+/** Prints the state of the matching object. Debug method.
+ */
+void SimilMeasureGreedy::_PrintPartsMatching()
+{
+	// assure that matching exists
+	assert(m_pMatching != NULL);
+
+	printf("Parts matching:\n");
+	m_pMatching->printMatching();
+}
+
+/** Comparison function required for qsort() call. Used while sorting groups of
+	Parts with respect to degree. Compares two TDN structures
+	with respect to their [1] field (degree). Highest degree goes first.
+	@param pElem1 Pointer to the TDN structure of some Part.
+	@param pElem2 Pointer to the TDN structure of some Part.
+	@return (-1) - pElem1 should go first, 0 - equal, (1) - pElem2 should go first.
+	*/
+int SimilMeasureGreedy::compareDegrees(const void *pElem1, const void *pElem2)
+{
+	int *tdn1 = (int *)pElem1;
+	int *tdn2 = (int *)pElem2;
+
+	if (tdn1[1] > tdn2[1])
+	{
+		// when degree - tdn1[1] - is BIGGER
+		return -1;
+	}
+	else
+		if (tdn1[1] < tdn2[1])
+		{
+			// when degree - tdn2[1] - is BIGGER
+			return 1;
+		}
+		else
+		{
+			return 0;
+		}
+}
+
+/** Comparison function required for qsort() call. Used while sorting groups of
+	Parts with respect to fuzzy vertex degree. Compares two TDN structures
+	with respect to their [4] field ( fuzzy vertex degree). Highest degree goes first.
+	@param pElem1 Pointer to the TDN structure of some Part.
+	@param pElem2 Pointer to the TDN structure of some Part.
+	@return (-1) - pElem1 should go first, 0 - equal, (1) - pElem2 should go first.
+	*/
+int SimilMeasureGreedy::compareFuzzyDegrees(const void *pElem1, const void *pElem2)
+{
+	int *tdn1 = (int *)pElem1;
+	int *tdn2 = (int *)pElem2;
+
+	if (tdn1[4] > tdn2[4])
+	{
+		// when degree - tdn1[4] - is BIGGER
+		return -1;
+	}
+	else
+		if (tdn1[4] < tdn2[4])
+		{
+			// when degree - tdn2[4] - is BIGGER
+			return 1;
+		}
+		else
+		{
+			return 0;
+		}
+}
+
+/** Comparison function required for qsort() call. Used while sorting groups of Parts with
+		the same degree. Firstly, compare NIt. Secondly, compare Neu. If both are equal -
+		compare Parts' original index (they are never equal). So this sorting assures
+		that the order obtained is deterministic.
+		@param pElem1 Pointer to the TDN structure of some Part.
+		@param pElem2 Pointer to the TDN structure of some Part.
+		@return (-1) - pElem1 should go first, 0 - equal, (1) - pElem2 should go first.
+		*/
+int SimilMeasureGreedy::compareConnsNo(const void *pElem1, const void *pElem2)
+{
+	// pointers to TDN arrays 
+	int *tdn1, *tdn2;
+	// definitions of elements being compared
+	tdn1 = (int *)pElem1;
+	tdn2 = (int *)pElem2;
+
+	// comparison according to Neural Connections (to jest TDN[2])
+	if (tdn1[NEUR_CONNS] > tdn2[NEUR_CONNS])
+	{
+		// when number of NConn Elem1 is BIGGER
+		return -1;
+	}
+	else
+		if (tdn1[NEUR_CONNS] < tdn2[NEUR_CONNS])
+		{
+			// when number of NConn Elem1 is SMALLER
+			return 1;
+		}
+		else
+		{
+			// when numbers of NConn are EQUAL
+			// compare Neu numbers (TDN[3])
+			if (tdn1[NEUROS] > tdn2[NEUROS])
+			{
+				// when number of Neu is BIGGER for Elem1 
+				return -1;
+			}
+			else
+				if (tdn1[NEUROS] < tdn2[NEUROS])
+				{
+					// when number of Neu is SMALLER for Elem1 
+					return 1;
+				}
+				else
+				{
+					// when numbers of Nconn and Neu are equal we check original indices 
+					// of Parts being compared
+
+					// comparison according to OrgIndex
+					if (tdn1[ORG_IND] > tdn2[ORG_IND])
+					{
+						// when the number of NIt Deg1 id BIGGER
+						return -1;
+					}
+					else
+						if (tdn1[ORG_IND] < tdn2[ORG_IND])
+						{
+							// when the number of NIt Deg1 id SMALLER
+							return 1;
+						}
+						else
+						{
+							// impossible, indices are alway different
+							return 0;
+						}
+				}
+		}
+}
+
+/** Returns number of factors involved in final distance computation.
+		These factors include differences in numbers of parts, degrees,
+		number of neurons.
+		*/
+int SimilMeasureGreedy::getNOFactors()
+{
+	return SimilMeasureGreedy::iNOFactors;
+}
+
+/** Prints the array of degrees for the given organism. Debug method.
+ */
+void SimilMeasureGreedy::_PrintDegrees(int i)
+{
+	int j;
+	printf("Organizm %i :", i);
+	printf("\n      ");
+	for (j = 0; j < models[i]->getPartCount(); j++)
+		printf("%3i ", j);
+	printf("\nInd:  ");
+	for (j = 0; j < models[i]->getPartCount(); j++)
+		printf("%3i ", (int)m_aDegrees[i][j][0]);
+	printf("\nDeg:  ");
+	for (j = 0; j < models[i]->getPartCount(); j++)
+		printf("%3i ", (int)m_aDegrees[i][j][1]);
+	printf("\nNIt:  ");
+	for (j = 0; j < models[i]->getPartCount(); j++)
+		printf("%3i ", (int)m_aDegrees[i][j][2]);
+	printf("\nNeu:  ");
+	for (j = 0; j < models[i]->getPartCount(); j++)
+		printf("%3i ", (int)m_aDegrees[i][j][3]);
+	printf("\n");
+}
+
+/** Prints one array of ints. Debug method.
+	@param array Base pointer of the array.
+	@param base First index of the array's element.
+	@param size Number of elements to print.
+	*/
+void SimilMeasureGreedy::_PrintArray(int *array, int base, int size)
+{
+	int i;
+	for (i = base; i < base + size; i++)
+	{
+		printf("%i ", array[i]);
+	}
+	printf("\n");
+}
+
+void SimilMeasureGreedy::_PrintArrayDouble(double *array, int base, int size)
+{
+	int i;
+	for (i = base; i < base + size; i++)
+	{
+		printf("%f ", array[i]);
+	}
+	printf("\n");
+}
+
+/** Prints one array of parts neighbourhood.
+	@param index of organism
+	*/
+void SimilMeasureGreedy::_PrintNeighbourhood(int o)
+{
+	assert(m_Neighbours[o] != 0);
+	printf("Neighbourhhod of organism %i\n", o);
+	int size = models[o]->getPartCount();
+	for (int i = 0; i < size; i++)
+	{
+		for (int j = 0; j < size; j++)
+		{
+			printf("%i ", m_Neighbours[o][i][j]);
+		}
+		printf("\n");
+	}
+}
+
+/** Prints one array of parts fuzzy neighbourhood.
+	@param index of organism
+	*/
+void SimilMeasureGreedy::_PrintFuzzyNeighbourhood(int o)
+{
+	assert(m_fuzzyNeighb[o] != NULL);
+	printf("Fuzzy neighbourhhod of organism %i\n", o);
+	int size = models[o]->getPartCount();
+	for (int i = 0; i < size; i++)
+	{
+		for (int j = 0; j < fuzzyDepth; j++)
+		{
+			printf("%f ", m_fuzzyNeighb[o][i][j]);
+		}
+		printf("\n");
+	}
+}
+
+int SimilMeasureGreedy::setParams(std::vector<double> params)
+{
+	int i = 0;
+	for (i = 0; i < SimilMeasureGreedy::iNOFactors; i++)
+		m_adFactors[i] = params.at(i);
+	fixedZaxis = params.at(i);
+	return 0;
+}
Index: /cpp/frams/model/similarity/measure-greedy.h
===================================================================
--- /cpp/frams/model/similarity/measure-greedy.h	(revision 1044)
+++ /cpp/frams/model/similarity/measure-greedy.h	(revision 1044)
@@ -0,0 +1,141 @@
+// This file is a part of Framsticks SDK.  http://www.framsticks.com/
+// Copyright (C) 1999-2020  Maciej Komosinski and Szymon Ulatowski.
+// See LICENSE.txt for details.
+
+#ifndef _GREEDY_MEASURE_H
+#define _GREEDY_MEASURE_H
+
+#include "measure-mds-based.h"
+#include "frams/genetics/geno.h"
+#include "frams/model/model.h"
+#include "simil-match.h"
+#include "measure-greedy.h"
+
+#define TDN_SIZE 5
+
+
+enum TDNELEMS2
+{
+	ORG_IND = 0,
+	DEG = 1,
+	NEUR_CONNS = 2,
+	NEUROS = 3,
+	FUZ_DEG = 4
+};
+
+class SimilMeasureGreedy : public SimilMeasureMDSBased
+{
+public:
+	SimilMeasureGreedy();
+	~SimilMeasureGreedy(){};
+
+	static int compareDegrees(const void *pElem1, const void *pElem2);
+	static int compareFuzzyDegrees(const void *pElem1, const void *pElem2);
+	static int compareConnsNo(const void *pElem1, const void *pElem2);
+	static int getNOFactors();
+	int setParams(std::vector<double> params);
+	/// Interface to local parameters
+	Param localpar;
+	/// Table of weights for weighted distance function.
+	/// Weights are for factors in the following order:
+	/// [0]: m_iDV (difference in the number of vertices)
+	/// [1]: m_iDD (difference in degrees over matching)
+	/// [2]: m_iDN (difference in neurons over matching)
+	/// [3]: m_dDG (difference in geometry over matching)
+	/// @sa EvaluateDistance
+	double m_adFactors[4];
+
+	//Controls the depth of fuzzy neighbourhood 
+	int fuzzyDepth;
+	bool isFuzzy;
+
+protected:
+	double distanceForTransformation();
+	double distanceWithoutAlignment();
+	void prepareData();
+	void beforeTransformation();
+	void computeMatching();
+	void copyMatching();
+	void cleanData();
+
+	int sortPartInfoTables();
+	int countPartNeurons();
+	int countPartDegrees();
+	int countPartsDistance();
+
+	void countFuzzyNeighb();
+	void sortFuzzyNeighb();
+	void getNeighbIndexes(int mod, int partInd, std::vector<int> &indexes);
+	void fuzzyOrder();
+	int createPartInfoTables();
+	
+	void _PrintArray(int *array, int base, int size);
+	void _PrintArrayDouble(double *array, int base, int size);
+	void _PrintDegrees(int i);
+	void _PrintNeighbourhood(int i);
+	void _PrintFuzzyNeighbourhood(int i);
+	void _PrintSeamnessTable(std::vector<int> *pVector, int iCount);
+	void _PrintPartsMatching();
+	void saveIntermediateFiles();
+
+	/// Number of parts of two creatures (index the same as for m_Mod).
+	int m_aiPartCount[2];
+
+	/// Difference between number of parts in organisms
+	int m_iDV;
+
+	/// Sum of absolute values of differences between matched part degrees
+	int m_iDD;
+
+	/// Sum of absolute values of differences between matched part 
+	/// in neurons number.
+	int m_iDN;
+	//2 matrices of neighbourhood of parts - one for each genotype 
+
+	/// Sum of Euclidean distances between matched parts
+	/// Unmatched Parts have the distance measured to (0,0,0) (the middle of
+	/// an organism)
+	double m_dDG;
+
+	/// Object that holds the matching of Parts.
+	SimilMatching *m_pMatching;
+	/// Object that holds temporary matching of Parts.
+	SimilMatching *tempMatching;
+
+	/// Type of 4 ints - describing one Part of the creature in
+	/// its sorted table of degrees
+	/// TDN[0] - original index of creature's Part (that is "i" from GetPart(i))
+	/// TDN[1] - degree (number of adjacent joints) of one Part
+	/// TDN[2] - number of NeuroConnections and Neurons belonging to one Part
+	/// TDN[3] - number of Neurons of the Part
+	/// TDN[4] - fuzzy degree
+	typedef int TDN[5];
+
+	/** 2 arrays holding information about compared organisms (one for each
+	creature) of degree and neuro info for Parts.
+	Index corresponds to the one in m_Mod
+	m_aDegrees[i][j] is a TDN of the j-th Part of the i-th creature in m_Mod
+	*/
+	TDN *m_aDegrees[2];
+
+	//std::pair<TDN, double> *m_aDegrees[2];
+	/// Holds information on all on-joint neurons. Only TDN[3] and TDN[4]
+	/// are important (original index and degree are not important).
+	TDN m_aOnJoint[2];
+
+	/// Holds information on all neurons that are not placed neither on
+	/// a joint nor on a part. Only TDN[3] and TDN[4]
+	/// are important (original index and degree are not important).
+	TDN m_aAnywhere[2];
+
+	//array of parts neighbourhood
+	int **m_Neighbours[2];
+	//array of "fuzzy neigbourhood" for each of organisms. Dimensions: parts_num x fuzzyDepth
+	float **m_fuzzyNeighb[2];
+
+	/// Number of weights in the function which evaluates distance.
+	static const int iNOFactors; 
+};
+
+#endif /* GREEDY_MEASURE_H */
+
Index: /cpp/frams/model/similarity/measure-hungarian.cpp
===================================================================
--- /cpp/frams/model/similarity/measure-hungarian.cpp	(revision 1044)
+++ /cpp/frams/model/similarity/measure-hungarian.cpp	(revision 1044)
@@ -0,0 +1,228 @@
+// This file is a part of Framsticks SDK.  http://www.framsticks.com/
+// Copyright (C) 1999-2020  Maciej Komosinski and Szymon Ulatowski.
+// See LICENSE.txt for details.
+
+#include "measure-hungarian.h"
+
+const int SimilMeasureHungarian::iNOFactors = 4;
+
+#define FIELDSTRUCT SimilMeasureHungarian
+
+static ParamEntry simil_hungarian_paramtab[] = {
+		{ "Similarity: hungarian", 1, 7, "similHungarianMeasure", "Evaluates morphological dissimilarity using hungarian measure. More information:\nhttp://www.framsticks.com/bib/Komosinski-et-al-2001\nhttp://www.framsticks.com/bib/Komosinski-and-Kubiak-2011\nhttp://www.framsticks.com/bib/Komosinski-2016\nhttps://doi.org/10.1007/978-3-030-16692-2_8", },
+		{ "simil_parts", 0, 0, "Weight of parts count", "f 0 100 0", FIELD(m_adFactors[0]), "Differing number of parts is also handled by the 'part degree' similarity component.", },
+		{ "simil_partdeg", 0, 0, "Weight of parts' degree", "f 0 100 1", FIELD(m_adFactors[1]), "", },
+		{ "simil_neuro", 0, 0, "Weight of neurons count", "f 0 100 0.1", FIELD(m_adFactors[2]), "", },
+		{ "simil_partgeom", 0, 0, "Weight of parts' geometric distances", "f 0 100 0", FIELD(m_adFactors[3]), "", },
+		{ "simil_fixedZaxis", 0, 0, "Fix 'z' (vertical) axis?", "d 0 1 0", FIELD(fixedZaxis), "", },
+		{ "simil_weightedMDS", 0, 0, "Should weighted MDS be used?", "d 0 1 0", FIELD(wMDS), "If activated, weighted MDS with vertex (i.e., Part) degrees as weights is used for 3D alignment of body structure.", },
+		{ "evaluateDistance", 0, PARAM_DONTSAVE | PARAM_USERHIDDEN, "evaluate model dissimilarity", "p f(oGeno,oGeno)", PROCEDURE(p_evaldistance), "Calculates dissimilarity between two models created from Geno objects.", },
+		{ 0, },
+};
+
+#undef FIELDSTRUCT
+
+SimilMeasureHungarian::SimilMeasureHungarian() : localpar(simil_hungarian_paramtab, this)
+{
+	localpar.setDefault();
+	
+	nSmaller = 0;
+	nBigger = 0;
+	
+	for (int i = 0; i < 2; i++)
+	{
+		degrees[i] = nullptr;
+		neurons[i] = nullptr;
+		on_joint[i] = 0;
+		anywhere[i] = 0;	
+	}
+	
+	assignment = nullptr;
+	parts_distances = nullptr;
+	temp_parts_distances = nullptr;
+	
+	save_matching = false;
+}
+
+void SimilMeasureHungarian::prepareData()
+{
+	m_iSmaller = models[0]->getPartCount() <= models[1]->getPartCount() ? 0 : 1;
+	nSmaller = models[m_iSmaller]->getPartCount();
+	nBigger = models[1 - m_iSmaller]->getPartCount();
+
+	for (int i = 0; i < 2; i++)
+	{
+		int size = models[i]->getPartCount();
+		degrees[i] = new int[size]();
+		neurons[i] = new int[size]();
+	}
+	
+	countDegrees();
+	countNeurons();
+	
+	parts_distances = new double[nBigger*nBigger]();
+	fillPartsDistances(parts_distances, nBigger, nSmaller, false);
+	assignment = new int[nBigger]();
+	
+	if (save_matching)
+		for (int i = 0; i < nBigger; i++)
+			min_assignment.push_back(0);
+}
+
+void SimilMeasureHungarian::beforeTransformation()
+{
+	temp_parts_distances = new double[nBigger*nBigger]();
+	std::copy(parts_distances, parts_distances + nBigger * nBigger, temp_parts_distances);
+}
+
+double SimilMeasureHungarian::distanceForTransformation()
+{
+	fillPartsDistances(temp_parts_distances, nBigger, nSmaller, true);
+	std::fill_n(assignment, nBigger, 0);
+	double distance = hungarian.Solve(temp_parts_distances, assignment, nBigger, nBigger);
+
+	delete[] temp_parts_distances;
+	return addNeuronsPartsDiff(distance);
+}
+
+double SimilMeasureHungarian::distanceWithoutAlignment()
+{
+	double distance = hungarian.Solve(parts_distances, assignment, nBigger, nBigger);
+	if (save_matching)
+		copyMatching();
+	return addNeuronsPartsDiff(distance);
+}
+
+double SimilMeasureHungarian::addNeuronsPartsDiff(double dist)
+{
+	//add difference in anywhere and onJoint neurons
+	dist += m_adFactors[2] * (abs(on_joint[0] - on_joint[1]) + abs(anywhere[0] - anywhere[1]));
+	//add difference in part numbers
+	dist += (nBigger - nSmaller) * m_adFactors[0];
+	return dist;
+}
+
+void SimilMeasureHungarian::copyMatching()
+{
+	min_assignment.clear();
+	min_assignment.insert(min_assignment.begin(), assignment, assignment + nBigger);
+}
+
+void SimilMeasureHungarian::cleanData()
+{
+	for (int i = 0; i < 2; i++)
+	{
+		// delete degree and position arrays
+		SAFEDELETEARRAY(degrees[i]);
+		SAFEDELETEARRAY(neurons[i]);	
+
+		on_joint[i] = 0;
+		anywhere[i] = 0;	
+	}
+
+	delete[] assignment;
+	delete[] parts_distances;
+	
+	if (save_matching)
+		min_assignment.clear();
+}
+
+void SimilMeasureHungarian::countDegrees()
+{
+	Part *P1, *P2;
+	int i, j, i1, i2;
+
+	for (i = 0; i < 2; i++)
+	{
+		for (j = 0; j < models[i]->getJointCount(); j++)
+		{
+			Joint *J = models[i]->getJoint(j);
+
+			P1 = J->part1;
+			P2 = J->part2;
+
+			i1 = models[i]->findPart(P1);
+			i2 = models[i]->findPart(P2);
+
+			degrees[i][i1]++;
+			degrees[i][i2]++;
+		}
+	}
+}
+
+void SimilMeasureHungarian::countNeurons()
+{
+	Part *P1;
+	Joint *J1;
+	int i, j, i2;
+
+	for (i = 0; i < 2; i++)
+	{
+		for (j = 0; j < models[i]->getNeuroCount(); j++)
+		{
+			Neuro *N = models[i]->getNeuro(j);
+			// count parts attached to neurons
+			P1 = N->getPart();
+			if (P1)
+			{
+				i2 = models[i]->findPart(P1);
+				neurons[i][i2]++;
+			}
+			else
+			// count unattached neurons
+			{
+				J1 = N->getJoint();
+				if (J1)
+					on_joint[i]++;
+				else
+					anywhere[i]++;
+			}
+		}
+	}
+}
+
+void SimilMeasureHungarian::fillPartsDistances(double*& dist, int bigger, int smaller, bool geo)
+{
+	for (int i = 0; i < bigger; i++)
+	{
+		for (int j = 0; j < bigger; j++)
+		{
+			// assign penalty for unassignment for vertex from bigger model
+			if (j >= smaller)
+			{
+				if (geo)
+					dist[i*bigger + j] += m_adFactors[3] * coordinates[1 - m_iSmaller][i].length();
+				else
+					dist[i*bigger + j] = m_adFactors[1] * degrees[1 - m_iSmaller][i] + m_adFactors[2] * neurons[1 - m_iSmaller][i];
+			}
+			// compute distance between parts
+			else
+			{
+				if (geo){
+					dist[i*bigger + j] += m_adFactors[3] * coordinates[1 - m_iSmaller][i].distanceTo(coordinates[m_iSmaller][j]);
+	}
+				else
+					dist[i*bigger + j] = m_adFactors[1] * abs(degrees[1 - m_iSmaller][i] - degrees[m_iSmaller][j])
+					+ m_adFactors[2] * abs(neurons[1 - m_iSmaller][i] - neurons[m_iSmaller][j]);
+			}
+		}
+	}
+}
+
+/** Returns number of factors involved in final distance computation.
+		These factors include differences in numbers of parts, degrees,
+		number of neurons.
+		*/
+int SimilMeasureHungarian::getNOFactors()
+{
+	return SimilMeasureHungarian::iNOFactors;
+}
+
+int SimilMeasureHungarian::setParams(std::vector<double> params)
+{
+	int i = 0;
+	for (i = 0; i < SimilMeasureHungarian::iNOFactors; i++)
+		m_adFactors[i] = params.at(i);
+	fixedZaxis = params.at(i);
+	return 0;
+}
Index: /cpp/frams/model/similarity/measure-hungarian.h
===================================================================
--- /cpp/frams/model/similarity/measure-hungarian.h	(revision 1044)
+++ /cpp/frams/model/similarity/measure-hungarian.h	(revision 1044)
@@ -0,0 +1,78 @@
+// This file is a part of Framsticks SDK.  http://www.framsticks.com/
+// Copyright (C) 1999-2020  Maciej Komosinski and Szymon Ulatowski.
+// See LICENSE.txt for details.
+
+#ifndef HUNGARIAN_MEASURE_H
+#define HUNGARIAN_MEASURE_H
+
+#include "measure-mds-based.h"
+#include "frams/genetics/geno.h"
+#include "frams/model/model.h"
+#include "hungarian/hungarian.h"
+
+class SimilMeasureHungarian : public SimilMeasureMDSBased
+{
+public:
+	SimilMeasureHungarian();
+	~SimilMeasureHungarian(){};
+	
+	double distanceForTransformation();
+	double distanceWithoutAlignment();
+	
+	static int getNOFactors();
+	int setParams(std::vector<double> params);
+
+	/// Table of weights for weighted distance function.
+	/// Weights are for factors in the following order:
+	/// [0]: m_iDV (difference in the number of vertices)
+	/// [1]: m_iDD (difference in degrees over matching)
+	/// [2]: m_iDN (difference in neurons over matching)
+	/// [3]: m_dDG (difference in geometry over matching)
+	/// @sa EvaluateDistance
+	double m_adFactors[4];
+	
+	/// Interface to local parameters
+	Param localpar;
+
+protected:
+	void prepareData();
+	void beforeTransformation();
+	void copyMatching();
+	void cleanData();
+	
+	void countDegrees();
+	void countNeurons();
+	void fillPartsDistances(double*& dist, int bigger, int smaller, bool geo);
+	double addNeuronsPartsDiff(double dist);
+	
+	//Smaller and greater structures sizes
+	int nSmaller;
+	int nBigger;
+	
+	//Vertex degrees for both structures
+	int *degrees[2];
+	
+	//Count of neurons attached to each parts for both structures
+	int *neurons[2];
+	
+	//Number of on-joint and unattached neurons for both structures
+	int on_joint[2];
+	int anywhere[2];
+	
+	//Temporary and final assignment
+	int *assignment;
+	std::vector<int> min_assignment;
+	
+	//Final and temporary parts distances
+	double* parts_distances;
+	double* temp_parts_distances;
+	
+	HungarianAlgorithm hungarian;
+	
+	/// Number of weights in the function which evaluates distance.
+	static const int iNOFactors;
+};
+
+
+#endif /* HUNGARIAN_MEASURE_H */
+
Index: /cpp/frams/model/similarity/measure-mds-based.cpp
===================================================================
--- /cpp/frams/model/similarity/measure-mds-based.cpp	(revision 1044)
+++ /cpp/frams/model/similarity/measure-mds-based.cpp	(revision 1044)
@@ -0,0 +1,213 @@
+// This file is a part of Framsticks SDK.  http://www.framsticks.com/
+// Copyright (C) 1999-2020  Maciej Komosinski and Szymon Ulatowski.
+// See LICENSE.txt for details.
+
+#include "measure-mds-based.h"
+#include "SVD/matrix_tools.h"
+
+SimilMeasureMDSBased::SimilMeasureMDSBased()
+{
+	coordinates[0] = nullptr;
+	coordinates[1] = nullptr;
+	
+	with_alignment = true;
+	save_matching = false;
+	fixedZaxis = 0;
+	wMDS = 1;
+}
+
+double SimilMeasureMDSBased::getDistance()
+{
+	double dResult = -1;
+	m_iSmaller = models[0]->getPartCount() <= models[1]->getPartCount() ? 0 : 1;
+
+	prepareData();
+	
+	if (with_alignment)
+	{
+		if (!getPartPositions())
+		{
+			logPrintf("SimilMDSBasedMeasure", "getDistance", LOG_ERROR, "Cannot compute part positions");
+			return -1;
+		}
+		
+		if (!computePartsPositionsByMDS())
+		{
+			logPrintf("SimilMDSBasedMeasure", "getDistance", LOG_ERROR, "Cannot perform MDS");
+			return -1;
+		}
+
+		// tutaj zacznij pętlę po przekształceniach  geometrycznych
+		const int NO_OF_TRANSFORM = 8; // liczba transformacji geometrycznych (na razie tylko ID i O_YZ)
+		// tablice transformacji współrzędnych; nie są to dokładnie tablice tranformacji, ale raczej tablice PRZEJŚĆ
+		// pomiędzy transformacjami; 
+		const int dMulX[NO_OF_TRANSFORM] = { 1, -1, -1, 1, -1, 1, -1, -1 };
+		const int dMulY[NO_OF_TRANSFORM] = { 1, 1, -1, -1, -1, -1, -1, 1 };
+		const int dMulZ[NO_OF_TRANSFORM] = { 1, 1, 1, -1, -1, -1, 1, 1 };
+
+		#ifdef max
+		#undef max //this macro would conflict with line below
+		#endif
+		double dMinSimValue = std::numeric_limits<double>::max(); // minimum value of similarity
+		
+		int iTransform; // a counter of geometric transformations
+		for (iTransform = 0; iTransform < NO_OF_TRANSFORM; iTransform++)
+		{
+			beforeTransformation();
+			
+			for (int iPart = 0; iPart < models[m_iSmaller]->getPartCount(); iPart++)
+			{
+				// for each iPart, a part of the model iMod
+				coordinates[m_iSmaller][iPart].x *= dMulX[iTransform];
+				coordinates[m_iSmaller][iPart].y *= dMulY[iTransform];
+				coordinates[m_iSmaller][iPart].z *= dMulZ[iTransform];
+			}
+			// now the positions are recomputed
+			double dCurrentSim = distanceForTransformation();
+
+			// załóż poprawną wartość podobieństwa
+			assert(dCurrentSim >= 0.0);
+
+			// porównaj wartość obliczoną z dotychczasowym minimum
+			if (dCurrentSim < dMinSimValue)
+			{
+			//printf("lesser sim\n");
+				dMinSimValue = dCurrentSim;
+				if (save_matching)
+					copyMatching();
+			}
+		}
+		
+		dResult = dMinSimValue;
+		
+		SAFEDELETEARRAY(coordinates[0]);
+		SAFEDELETEARRAY(coordinates[1]);
+	}
+	else
+	{
+		dResult = distanceWithoutAlignment();
+	}
+
+	cleanData();
+
+	return dResult;
+}
+
+
+/** Gets information about Parts' positions in 3D from models into the arrays
+		coordinates.
+		Assumptions:
+		- Models (models) are created and available.
+		- Arrays coordinates are created.
+		@return 1 if success, otherwise 0.
+		*/
+int SimilMeasureMDSBased::getPartPositions()
+{	
+	// for each model copy its part coordinates
+	Part *pPart;
+	for (int iMod = 0; iMod < 2; iMod++)
+	{
+		// utworz tablice dla pozycji 3D Parts (wielkosc tablicy: liczba Parts organizmu)
+		coordinates[iMod] = new Pt3D[models[iMod]->getPartCount()];
+		assert(coordinates[iMod] != NULL);
+		// dla każdego z modeli iMod
+		for (int iPart = 0; iPart < models[iMod]->getPartCount(); iPart++)
+		{
+			// dla każdego iPart organizmu iMod
+			// pobierz tego Part
+			pPart = models[iMod]->getPart(iPart);
+			// zapamietaj jego pozycje 3D w tablicy coordinates
+			coordinates[iMod][iPart].x = pPart->p.x;
+			coordinates[iMod][iPart].y = pPart->p.y;
+			coordinates[iMod][iPart].z = pPart->p.z;
+		}
+	}
+
+	return 1;
+}
+
+bool SimilMeasureMDSBased::computePartsPositionsByMDS()
+{
+	bool bResult = true;
+	
+	// use MDS to obtain different point of view on organisms
+	// and store the new positions (currently the original ones are still stored)
+	for (int iMod = 0; iMod < 2; iMod++)
+	{
+		// prepare the vector of errors of approximation for the SVD
+		std::vector<double> vEigenvalues;
+		int nSize = models[iMod]->getPartCount();
+
+		double *pDistances = new double[nSize * nSize];
+
+		for (int i = 0; i < nSize; i++)
+		{
+			pDistances[i] = 0;
+		}
+
+		Model *pModel = models[iMod]; // use the model of the iMod (current) organism
+		int iP1, iP2; // indices of Parts in the model
+		Part *P1, *P2; // pointers to Parts
+		Pt3D P1Pos, P2Pos; // positions of parts 
+		double dDistance; // the distance between Parts
+
+		double *weights = new double[nSize];
+		for (int i = 0; i < nSize; i++)
+		{
+			if (wMDS == 1)
+				weights[i] = 0;
+			else
+				weights[i] = 1;
+		}
+
+		if (wMDS == 1)
+			for (int i = 0; i < pModel->getJointCount(); i++)
+			{
+				weights[pModel->getJoint(i)->p1_refno]++;
+				weights[pModel->getJoint(i)->p2_refno]++;
+			}
+
+		for (iP1 = 0; iP1 < pModel->getPartCount(); iP1++)
+		{
+			// for each iP1, a Part index in the model of organism iMod
+			P1 = pModel->getPart(iP1);
+			// get the position of the Part
+			P1Pos = P1->p;
+			if (fixedZaxis == 1)
+			{
+				P1Pos.z = 0; //fixed vertical axis, so pretend all points are on the xy plane
+			}
+			for (iP2 = 0; iP2 < pModel->getPartCount(); iP2++)
+			{
+				// for each (iP1, iP2), a pair of Parts index in the model
+				P2 = pModel->getPart(iP2);
+				// get the position of the Part
+				P2Pos = P2->p;
+				if (fixedZaxis == 1)
+				{
+					P2Pos.z = 0; //fixed vertical axis, so pretend all points are on the xy plane
+				}
+				// compute the geometric (Euclidean) distance between the Parts
+				dDistance = P1Pos.distanceTo(P2Pos);
+				// store the distance
+				pDistances[iP1 * nSize + iP2] = dDistance;
+			} // for (iP2)
+		} // for (iP1)
+		
+		MatrixTools::weightedMDS(vEigenvalues, nSize, pDistances, coordinates[iMod], weights);
+		
+		if (fixedZaxis == 1) //restore the original vertical coordinate of each Part
+		{
+			for (int part = 0; part < pModel->getPartCount(); part++)
+			{
+				coordinates[iMod][part].z = pModel->getPart(part)->p.z;
+			}
+		}
+		
+		delete[] pDistances;
+		delete[] weights;
+	}
+
+	return bResult;
+}
+
Index: /cpp/frams/model/similarity/measure-mds-based.h
===================================================================
--- /cpp/frams/model/similarity/measure-mds-based.h	(revision 1044)
+++ /cpp/frams/model/similarity/measure-mds-based.h	(revision 1044)
@@ -0,0 +1,36 @@
+// This file is a part of Framsticks SDK.  http://www.framsticks.com/
+// Copyright (C) 1999-2020  Maciej Komosinski and Szymon Ulatowski.
+// See LICENSE.txt for details.
+
+#ifndef _SIMIL_MEASURE_MDS_BASED_H
+#define _SIMIL_MEASURE_MDS_BASED_H
+
+#include "simil-measure.h"
+
+class SimilMeasureMDSBased : public SimilMeasure
+{
+public:
+	SimilMeasureMDSBased();
+	virtual ~SimilMeasureMDSBased(){};
+	virtual int setParams(std::vector<double> params)=0;
+	bool with_alignment;
+	bool save_matching;
+	int fixedZaxis;
+	int wMDS;
+protected:
+	double getDistance();
+	virtual void prepareData()=0;
+	virtual void beforeTransformation()=0;
+	virtual double distanceForTransformation()=0;
+	virtual double distanceWithoutAlignment()=0;
+	int getPartPositions();
+	bool computePartsPositionsByMDS();
+	virtual void copyMatching()=0;
+	virtual void cleanData()=0;
+	int m_iSmaller;
+	/// Positions of Parts of both of the compared structures. 
+	Pt3D *coordinates[2];
+};
+
+#endif
+
Index: /cpp/frams/model/similarity/simil-match.cpp
===================================================================
--- /cpp/frams/model/similarity/simil-match.cpp	(revision 1044)
+++ /cpp/frams/model/similarity/simil-match.cpp	(revision 1044)
@@ -0,0 +1,264 @@
+// This file is a part of Framsticks SDK.  http://www.framsticks.com/
+// Copyright (C) 1999-2020  Maciej Komosinski and Szymon Ulatowski.
+// See LICENSE.txt for details.
+
+#include <assert.h>
+#include <stdio.h>
+#include "simil-match.h"
+
+/** Creates an empty matching for two objects of specified size.
+		@param Obj0Size Size of the first object. Must be positive.
+		@param Obj1Size Size of the second object. Must be positive.
+ */
+SimilMatching::SimilMatching(int Obj0Size, int Obj1Size)
+{
+	// assure that sizes of objects are positive
+	assert(Obj0Size > 0);
+	assert(Obj1Size > 0);
+
+	// create necessary vectors
+	m_apvMatched[0] = new std::vector<int>(Obj0Size);
+	m_apvMatched[1] = new std::vector<int>(Obj1Size);
+
+	// assure that vectors are created
+	assert(m_apvMatched[0] != NULL);
+	assert(m_apvMatched[1] != NULL);
+
+	// fill vectors with "unmatched" indicator
+	for (unsigned int i = 0; i < m_apvMatched[0]->size(); i++)
+	{
+		m_apvMatched[0]->operator[](i) = -1;
+	}
+	for (unsigned int i = 0; i < m_apvMatched[1]->size(); i++)
+	{
+		m_apvMatched[1]->operator[](i) = -1;
+	}
+}
+
+/** A copying constructor.
+		@param Source The object to be copied.
+ */
+SimilMatching::SimilMatching(const SimilMatching &Source)
+{
+	// copy the vectors of the actual matching
+	m_apvMatched[0] = new std::vector<int>(*(Source.m_apvMatched[0]));
+	m_apvMatched[1] = new std::vector<int>(*(Source.m_apvMatched[1]));
+
+	// assure that vectors are created
+	assert(m_apvMatched[0] != NULL);
+	assert(m_apvMatched[1] != NULL);
+}
+
+/** Destroys a matching object.
+ */
+SimilMatching::~SimilMatching()
+{
+	// delete vectors of matching
+	delete m_apvMatched[0];
+	delete m_apvMatched[1];
+}
+
+/** Gets size of the specified object.
+		@param Index of an object (must be 0 or 1).
+		@return Size of the object (in elements).
+ */
+int SimilMatching::getObjectSize(int Obj)
+{
+	// check parameter
+	assert((Obj == 0) || (Obj == 1));
+
+	// return the result
+	return m_apvMatched[Obj]->size();
+}
+
+/** Matches elements given by indices in the given objects.
+		@param Obj0 Index of the first object. Must be 0 or 1.
+		@param index0 Index of element in the first object. Must be a valid index
+		( >= 0 and < size of the object).
+		@param Obj1 Index of the second object. Must be 0 or 1 and different from Obj0.
+		@param Index1 index of element in the second object. Must be a valid index
+		( >= 0 and < size of the object).
+
+ */
+void SimilMatching::match(int Obj0, int Index0, int Obj1, int Index1)
+{
+	// check parameters of object 0
+	assert((Obj0 == 0) || (Obj0 == 1));
+	assert((Index0 >= 0) && (Index0 < (int)m_apvMatched[Obj0]->size()));
+	// check parameters of object 1
+	assert(((Obj1 == 0) || (Obj1 == 1)) && (Obj0 != Obj1));
+	assert((Index1 >= 0) && (Index1 < (int)m_apvMatched[Obj1]->size()));
+
+	// match given elements
+	// matching_Obj0(Index0) = Index1
+	m_apvMatched[Obj0]->operator[](Index0) = Index1;
+	// matching_Obj1(Index1) = Index0
+	m_apvMatched[Obj1]->operator[](Index1) = Index0;
+}
+
+/** Checks if the given element in the given object is already matched.
+		@param Obj Index of an object (must be 0 or 1).
+		@param Index Index of an element in the given object. Must be a valid index
+		( >=0 and < size of the object).
+		@return true if the given element is matched, false otherwise.
+ */
+bool SimilMatching::isMatched(int Obj, int Index)
+{
+	// check parameters
+	assert((Obj == 0) || (Obj == 1));
+	assert((Index >= 0) && (Index < (int)m_apvMatched[Obj]->size()));
+
+	// check if the element is matched
+	if (m_apvMatched[Obj]->operator[](Index) >= 0)
+	{
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+/** Gets index of the element thet is matched in the other object withe the element given
+		by parameters.
+		@param Obj Index of an object (must be 0 or 1).
+		@param Index Index of checked element in the given object.
+		@return Index of the element (in the other organism) that is matched with the given
+		element. WARNING! If the given element is not matched, the result may be smaller than 0
+		(check IsMatched() before using GetMatchedIndex()).
+ */
+int SimilMatching::getMatchedIndex(int Obj, int Index)
+{
+	// check parameters
+	assert((Obj == 0) || (Obj == 1));
+	assert((Index >= 0) && (Index < (int)m_apvMatched[Obj]->size()));
+
+	// return the index of the matched element
+	return m_apvMatched[Obj]->operator[](Index);
+}
+
+/** Checks if the matching is already full, i.e. if the smaller object already has all its
+		elements matched.
+		@return true if matching is full, false otherwise.
+ */
+bool SimilMatching::isFull()
+{
+	// assume that the matching is full
+	bool bResult = true;
+	// index of the smallest object
+	int nObj;
+
+	// find the smallest object (its index)
+	if (m_apvMatched[0]->size() < m_apvMatched[1]->size())
+	{
+		nObj = 0;
+	}
+	else
+	{
+		nObj = 1;
+	}
+
+	// check if all elements of the smallest object are matched
+	for (unsigned int nElem = 0; nElem < m_apvMatched[nObj]->size(); nElem++)
+	{
+		if (m_apvMatched[nObj]->operator[](nElem) < 0)
+		{
+			// if any element is not matched, the result is false
+			bResult = false;
+			break;
+		}
+	}
+
+	// return the result
+	return bResult;
+}
+
+/** Checks if the matching is empty (i.e. none of elements is matched).
+	@return true if matching is empty, otherwise - false.
+ */
+bool SimilMatching::isEmpty()
+{
+	// result - assume that matching is empty
+	bool bResult = true;
+
+	// matching is empty if either of objects has only unmatched elements
+	// so it may be first object 
+	int nObj = 0;
+	for (unsigned int nElem = 0; nElem < m_apvMatched[nObj]->size(); nElem++)
+	{
+		if (m_apvMatched[nObj]->operator[](nElem) >= 0)
+		{
+			// if any element of the object is matched (unmatched objects have (-1))
+			bResult = false;
+			break;
+		}
+	}
+
+	// return the result from the loop
+	return bResult;
+}
+
+/** Makes the matching completely empty. After a call to this method IsEmpty() should return true.
+ */
+void SimilMatching::empty()
+{
+	for (int iObj = 0; iObj < 2; iObj++) // a counter of objects
+	{
+		// for each object in the matching
+		for (unsigned int iElem = 0; iElem < m_apvMatched[iObj]->size(); iElem++) // a counter of objects' elements
+		{
+			// for each element iElem for the object iObj
+			// set it as unmatched (marker: -1)
+			m_apvMatched[iObj]->operator[](iElem) = -1;
+		}
+	}
+
+	// the exit condition
+	assert(isEmpty() == true);
+}
+
+/** Prints the current state of the matching
+ */
+void SimilMatching::printMatching()
+{
+	int nBigger;
+
+	// check which object is bigger
+	if (m_apvMatched[0]->size() >= m_apvMatched[1]->size())
+	{
+		nBigger = 0;
+	}
+	else
+	{
+		nBigger = 1;
+	}
+
+	// print first line - indices of objects
+	printf("[ ");
+	for (unsigned int i = 0; i < m_apvMatched[nBigger]->size(); i++)
+	{
+		printf("%2d ", i);
+	}
+	printf("]\n");
+
+	// print second line and third - indices of elements matched with elements of the objects
+	for (int nObj = 0; nObj < 2; nObj++)
+	{
+		// for both objects - print out lines of matched elements
+		printf("[ ");
+		for (unsigned int i = 0; i < m_apvMatched[nObj]->size(); i++)
+		{
+			if (isMatched(nObj, i))
+			{
+				// if the element is matched - print the index
+				printf("%2d ", getMatchedIndex(nObj, i));
+			}
+			else
+			{
+				// if the element is not matched - print "X"
+				printf(" X ");
+			}
+		}
+		printf("]\n");
+	}
+}
Index: /cpp/frams/model/similarity/simil-match.h
===================================================================
--- /cpp/frams/model/similarity/simil-match.h	(revision 1044)
+++ /cpp/frams/model/similarity/simil-match.h	(revision 1044)
@@ -0,0 +1,38 @@
+// This file is a part of Framsticks SDK.  http://www.framsticks.com/
+// Copyright (C) 1999-2020  Maciej Komosinski and Szymon Ulatowski.
+// See LICENSE.txt for details.
+
+#ifndef SIMILMATCHING_H
+#define SIMILMATCHING_H
+
+#include <vector>
+
+/** This class describes a mutually single-valued function between two sets of elements
+	(these sets are called objects). These sets may have different sizes, so this function
+	is mutually single-valued only for some subset of the bigger set.
+	This class is used while building a matching function between Parts of two Framsticks'
+	organisms (similarity measure computation).
+ */
+class SimilMatching
+{
+protected:
+	/** Array of pointers to two vectors. Each one stores indices of matched elements of
+		the other object. Value <0 means that an element is not matched yet. Sizes of these
+		vectors are sizes of objects themselves.
+	 */
+	std::vector<int> *m_apvMatched[2];
+public:
+	SimilMatching(int Obj0Size, int Obj1Size);
+	SimilMatching(const SimilMatching &Source);
+	~SimilMatching();
+	int getObjectSize(int Obj);
+	void match(int Obj0, int Index0, int Obj1, int Index1);
+	bool isMatched(int Obj, int Index);
+	int getMatchedIndex(int Obj, int index);
+	bool isFull();
+	bool isEmpty();
+	void empty();
+	void printMatching();
+};
+
+#endif
Index: /cpp/frams/model/similarity/simil-measure.cpp
===================================================================
--- /cpp/frams/model/similarity/simil-measure.cpp	(revision 1044)
+++ /cpp/frams/model/similarity/simil-measure.cpp	(revision 1044)
@@ -0,0 +1,96 @@
+// This file is a part of Framsticks SDK.  http://www.framsticks.com/
+// Copyright (C) 1999-2020  Maciej Komosinski and Szymon Ulatowski.
+// See LICENSE.txt for details.
+
+#include "simil-measure.h"
+#include <frams/vm/classes/genoobj.h>
+#include <frams/model/geometry/meshbuilder.h>
+#include <frams/_demos/geometry/geometrytestutils.h>
+
+#define FIELDSTRUCT SimilMeasure
+
+static ParamEntry simil_measure_paramtab[] = {
+	{ "Similarity", 1, 2, "SimilMeasure", "Evaluates morphological dissimilarity.", },
+	{ "measure_type", 0, 0, "Type of similarity measure", "d 1 3 1", FIELD(measure_type), "", },
+	{ "evaluateDistance", 0, PARAM_DONTSAVE | PARAM_USERHIDDEN, "evaluate model dissimilarity", "p f(oGeno,oGeno)", PROCEDURE(p_evaldistance), "Calculates dissimilarity between two models created from Geno objects.", },
+	{ 0, },
+};
+
+#undef FIELDSTRUCT
+
+SimilMeasure::SimilMeasure() : localpar(simil_measure_paramtab, this)
+{
+	for (int i = 0; i < 2; i++)
+	{
+		genos[i] = nullptr;
+		models[i] = nullptr;
+	}
+	localpar.setDefault();
+}
+
+double SimilMeasure::evaluateDistance(const Geno* G0, const Geno* G1)
+{
+	genos[0] = G0;
+	genos[1] = G1;
+
+	// create models of objects to compare
+	models[0] = newModel(genos[0]);
+	models[1] = newModel(genos[1]);
+
+	if (models[0] == NULL || models[1] == NULL)
+	{
+		logPrintf("SimilarityMeasure", "EvaluateDistance", LOG_ERROR, "Unable to create model from one of the genotypes.");
+		return -1;
+	}
+	
+	double distance = getDistance();
+	SAFEDELETE(models[0]);
+	SAFEDELETE(models[1]);
+	return distance;
+}
+
+Model* SimilMeasure::newModel(const Geno *g)
+{
+	if (g == NULL)
+	{
+		logPrintf("SimilarityMeasure", "newModel", LOG_ERROR, "NULL genotype pointer");
+		return NULL;
+	}
+	Model *m = new Model(*g, ModelEnum::SHAPETYPE_UNKNOWN);
+	if (!m->isValid())
+	{
+		logPrintf("SimilarityMeasure", "newModel", LOG_ERROR, "Invalid model for the genotype of '%s'", g->getName().c_str());
+		delete m;
+		return NULL;
+	}
+	return m;
+}
+
+void SimilMeasure::p_evaldistance(ExtValue *args, ExtValue *ret)
+{
+	Geno *g1 = GenoObj::fromObject(args[1]);
+	Geno *g2 = GenoObj::fromObject(args[0]);
+	if ((!g1) || (!g2))
+		ret->setEmpty();
+	else
+		ret->setDouble(evaluateDistance(g1, g2));
+}
+
+Model SimilMeasure::sampleSurface(Model* M, double density)
+{
+    Model resultModel;
+    resultModel.open();
+    GeometryTestUtils::addAnchorToModel(resultModel);
+
+    MeshBuilder::ModelSurface iterator(density);
+    iterator.initialize(M);
+
+    Pt3D point;
+    while (iterator.tryGetNext(point))
+    {
+        GeometryTestUtils::addPointToModel(point, resultModel);
+    }
+
+    resultModel.close();
+    return resultModel;
+}
Index: /cpp/frams/model/similarity/simil-measure.h
===================================================================
--- /cpp/frams/model/similarity/simil-measure.h	(revision 1044)
+++ /cpp/frams/model/similarity/simil-measure.h	(revision 1044)
@@ -0,0 +1,39 @@
+// This file is a part of Framsticks SDK.  http://www.framsticks.com/
+// Copyright (C) 1999-2020  Maciej Komosinski and Szymon Ulatowski.
+// See LICENSE.txt for details.
+
+#ifndef _SIMIL_MEASURE_H
+#define _SIMIL_MEASURE_H
+
+#include "frams/genetics/geno.h"
+#include "frams/model/model.h"
+#include <assert.h>
+
+class SimilMeasure
+{
+public:
+	SimilMeasure();
+	int measure_type;
+	/// Interface to local parameters
+	Param localpar;
+
+	virtual ~SimilMeasure(){};
+	virtual double getDistance() = 0;
+	double evaluateDistance(const Geno *G0, const Geno *G1);
+	virtual int setParams(std::vector<double> params) = 0;
+    Model sampleSurface(Model *M, double density);
+
+	#define STATRICKCLASS SimilMeasure
+	PARAMPROCDEF(p_evaldistance);
+	#undef STATRICKCLASS
+
+protected:
+	/// Genotypes between which distance is evaluated.
+	const Geno *genos[2];
+	/// Models created from the genotypes array
+	Model *models[2];
+	Model* newModel(const Geno *g);
+};
+
+#endif
+
Index: p/frams/model/similarity/simil_match.cpp
===================================================================
--- /cpp/frams/model/similarity/simil_match.cpp	(revision 1043)
+++ 	(revision )
@@ -1,264 +1,0 @@
-// This file is a part of Framsticks SDK.  http://www.framsticks.com/
-// Copyright (C) 1999-2019  Maciej Komosinski and Szymon Ulatowski.
-// See LICENSE.txt for details.
-
-#include <assert.h>
-#include <stdio.h>
-#include "simil_match.h"
-
-/** Creates an empty matching for two objects of specified size.
-		@param Obj0Size Size of the first object. Must be positive.
-		@param Obj1Size Size of the second object. Must be positive.
- */
-SimilMatching::SimilMatching(int Obj0Size, int Obj1Size)
-{
-	// assure that sizes of objects are positive
-	assert(Obj0Size > 0);
-	assert(Obj1Size > 0);
-
-	// create necessary vectors
-	m_apvMatched[0] = new std::vector<int>(Obj0Size);
-	m_apvMatched[1] = new std::vector<int>(Obj1Size);
-
-	// assure that vectors are created
-	assert(m_apvMatched[0] != NULL);
-	assert(m_apvMatched[1] != NULL);
-
-	// fill vectors with "unmatched" indicator
-	for (unsigned int i = 0; i < m_apvMatched[0]->size(); i++)
-	{
-		m_apvMatched[0]->operator[](i) = -1;
-	}
-	for (unsigned int i = 0; i < m_apvMatched[1]->size(); i++)
-	{
-		m_apvMatched[1]->operator[](i) = -1;
-	}
-}
-
-/** A copying constructor.
-		@param Source The object to be copied.
- */
-SimilMatching::SimilMatching(const SimilMatching &Source)
-{
-	// copy the vectors of the actual matching
-	m_apvMatched[0] = new std::vector<int>(*(Source.m_apvMatched[0]));
-	m_apvMatched[1] = new std::vector<int>(*(Source.m_apvMatched[1]));
-
-	// assure that vectors are created
-	assert(m_apvMatched[0] != NULL);
-	assert(m_apvMatched[1] != NULL);
-}
-
-/** Destroys a matching object.
- */
-SimilMatching::~SimilMatching()
-{
-	// delete vectors of matching
-	delete m_apvMatched[0];
-	delete m_apvMatched[1];
-}
-
-/** Gets size of the specified object.
-		@param Index of an object (must be 0 or 1).
-		@return Size of the object (in elements).
- */
-int SimilMatching::GetObjectSize(int Obj)
-{
-	// check parameter
-	assert((Obj == 0) || (Obj == 1));
-
-	// return the result
-	return m_apvMatched[Obj]->size();
-}
-
-/** Matches elements given by indices in the given objects.
-		@param Obj0 Index of the first object. Must be 0 or 1.
-		@param index0 Index of element in the first object. Must be a valid index
-		( >= 0 and < size of the object).
-		@param Obj1 Index of the second object. Must be 0 or 1 and different from Obj0.
-		@param Index1 index of element in the second object. Must be a valid index
-		( >= 0 and < size of the object).
-
- */
-void SimilMatching::Match(int Obj0, int Index0, int Obj1, int Index1)
-{
-	// check parameters of object 0
-	assert((Obj0 == 0) || (Obj0 == 1));
-	assert((Index0 >= 0) && (Index0 < (int)m_apvMatched[Obj0]->size()));
-	// check parameters of object 1
-	assert(((Obj1 == 0) || (Obj1 == 1)) && (Obj0 != Obj1));
-	assert((Index1 >= 0) && (Index1 < (int)m_apvMatched[Obj1]->size()));
-
-	// match given elements
-	// matching_Obj0(Index0) = Index1
-	m_apvMatched[Obj0]->operator[](Index0) = Index1;
-	// matching_Obj1(Index1) = Index0
-	m_apvMatched[Obj1]->operator[](Index1) = Index0;
-}
-
-/** Checks if the given element in the given object is already matched.
-		@param Obj Index of an object (must be 0 or 1).
-		@param Index Index of an element in the given object. Must be a valid index
-		( >=0 and < size of the object).
-		@return true if the given element is matched, false otherwise.
- */
-bool SimilMatching::IsMatched(int Obj, int Index)
-{
-	// check parameters
-	assert((Obj == 0) || (Obj == 1));
-	assert((Index >= 0) && (Index < (int)m_apvMatched[Obj]->size()));
-
-	// check if the element is matched
-	if (m_apvMatched[Obj]->operator[](Index) >= 0)
-	{
-		return true;
-	}
-	else
-	{
-		return false;
-	}
-}
-
-/** Gets index of the element thet is matched in the other object withe the element given
-		by parameters.
-		@param Obj Index of an object (must be 0 or 1).
-		@param Index Index of checked element in the given object.
-		@return Index of the element (in the other organism) that is matched with the given
-		element. WARNING! If the given element is not matched, the result may be smaller than 0
-		(check IsMatched() before using GetMatchedIndex()).
- */
-int SimilMatching::GetMatchedIndex(int Obj, int Index)
-{
-	// check parameters
-	assert((Obj == 0) || (Obj == 1));
-	assert((Index >= 0) && (Index < (int)m_apvMatched[Obj]->size()));
-
-	// return the index of the matched element
-	return m_apvMatched[Obj]->operator[](Index);
-}
-
-/** Checks if the matching is already full, i.e. if the smaller object already has all its
-		elements matched.
-		@return true if matching is full, false otherwise.
- */
-bool SimilMatching::IsFull()
-{
-	// assume that the matching is full
-	bool bResult = true;
-	// index of the smallest object
-	int nObj;
-
-	// find the smallest object (its index)
-	if (m_apvMatched[0]->size() < m_apvMatched[1]->size())
-	{
-		nObj = 0;
-	}
-	else
-	{
-		nObj = 1;
-	}
-
-	// check if all elements of the smallest object are matched
-	for (unsigned int nElem = 0; nElem < m_apvMatched[nObj]->size(); nElem++)
-	{
-		if (m_apvMatched[nObj]->operator[](nElem) < 0)
-		{
-			// if any element is not matched, the result is false
-			bResult = false;
-			break;
-		}
-	}
-
-	// return the result
-	return bResult;
-}
-
-/** Checks if the matching is empty (i.e. none of elements is matched).
-	@return true if matching is empty, otherwise - false.
- */
-bool SimilMatching::IsEmpty()
-{
-	// result - assume that matching is empty
-	bool bResult = true;
-
-	// matching is empty if either of objects has only unmatched elements
-	// so it may be first object 
-	int nObj = 0;
-	for (unsigned int nElem = 0; nElem < m_apvMatched[nObj]->size(); nElem++)
-	{
-		if (m_apvMatched[nObj]->operator[](nElem) >= 0)
-		{
-			// if any element of the object is matched (unmatched objects have (-1))
-			bResult = false;
-			break;
-		}
-	}
-
-	// return the result from the loop
-	return bResult;
-}
-
-/** Makes the matching completely empty. After a call to this method IsEmpty() should return true.
- */
-void SimilMatching::Empty()
-{
-	for (int iObj = 0; iObj < 2; iObj++) // a counter of objects
-	{
-		// for each object in the matching
-		for (unsigned int iElem = 0; iElem < m_apvMatched[iObj]->size(); iElem++) // a counter of objects' elements
-		{
-			// for each element iElem for the object iObj
-			// set it as unmatched (marker: -1)
-			m_apvMatched[iObj]->operator[](iElem) = -1;
-		}
-	}
-
-	// the exit condition
-	assert(IsEmpty() == true);
-}
-
-/** Prints the current state of the matching
- */
-void SimilMatching::PrintMatching()
-{
-	int nBigger;
-
-	// check which object is bigger
-	if (m_apvMatched[0]->size() >= m_apvMatched[1]->size())
-	{
-		nBigger = 0;
-	}
-	else
-	{
-		nBigger = 1;
-	}
-
-	// print first line - indices of objects
-	printf("[ ");
-	for (unsigned int i = 0; i < m_apvMatched[nBigger]->size(); i++)
-	{
-		printf("%2d ", i);
-	}
-	printf("]\n");
-
-	// print second line and third - indices of elements matched with elements of the objects
-	for (int nObj = 0; nObj < 2; nObj++)
-	{
-		// for both objects - print out lines of matched elements
-		printf("[ ");
-		for (unsigned int i = 0; i < m_apvMatched[nObj]->size(); i++)
-		{
-			if (IsMatched(nObj, i))
-			{
-				// if the element is matched - print the index
-				printf("%2d ", GetMatchedIndex(nObj, i));
-			}
-			else
-			{
-				// if the element is not matched - print "X"
-				printf(" X ");
-			}
-		}
-		printf("]\n");
-	}
-}
Index: p/frams/model/similarity/simil_match.h
===================================================================
--- /cpp/frams/model/similarity/simil_match.h	(revision 1043)
+++ 	(revision )
@@ -1,38 +1,0 @@
-// This file is a part of Framsticks SDK.  http://www.framsticks.com/
-// Copyright (C) 1999-2019  Maciej Komosinski and Szymon Ulatowski.
-// See LICENSE.txt for details.
-
-#ifndef SIMILMATCHING_H
-#define SIMILMATCHING_H
-
-#include <vector>
-
-/** This class describes a mutually single-valued function between two sets of elements
-	(these sets are called objects). These sets may have different sizes, so this function
-	is mutually single-valued only for some subset of the bigger set.
-	This class is used while building a matching function between Parts of two Framsticks'
-	organisms (similarity measure computation).
- */
-class SimilMatching
-{
-protected:
-	/** Array of pointers to two vectors. Each one stores indices of matched elements of
-		the other object. Value <0 means that an element is not matched yet. Sizes of these
-		vectors are sizes of objects themselves.
-	 */
-	std::vector<int> *m_apvMatched[2];
-public:
-	SimilMatching(int Obj0Size, int Obj1Size);
-	SimilMatching(const SimilMatching &Source);
-	~SimilMatching();
-	int GetObjectSize(int Obj);
-	void Match(int Obj0, int Index0, int Obj1, int Index1);
-	bool IsMatched(int Obj, int Index);
-	int GetMatchedIndex(int Obj, int index);
-	bool IsFull();
-	bool IsEmpty();
-	void Empty();
-	void PrintMatching();
-};
-
-#endif
Index: /cpp/tests/similarity-tests.txt
===================================================================
--- /cpp/tests/similarity-tests.txt	(revision 1043)
+++ /cpp/tests/similarity-tests.txt	(revision 1044)
@@ -11,5 +11,5 @@
 TESTNAME:parts weight
 arg:similarity.gen
-arg:0
+arg:hungarian
 arg:1
 arg:0
@@ -22,5 +22,5 @@
 TESTNAME:degrees weight
 arg:similarity.gen
-arg:0
+arg:hungarian
 arg:0
 arg:1
@@ -33,5 +33,5 @@
 TESTNAME:neurons weight
 arg:similarity.gen
-arg:0
+arg:hungarian
 arg:0
 arg:0
@@ -44,5 +44,5 @@
 TESTNAME:distances weight greedy
 arg:similarity.gen
-arg:1
+arg:greedy
 arg:0
 arg:0
@@ -55,5 +55,5 @@
 TESTNAME:all weights greedy
 arg:similarity.gen
-arg:1
+arg:greedy
 arg:1
 arg:1
@@ -66,5 +66,5 @@
 TESTNAME:all weights fixed z greedy
 arg:similarity.gen
-arg:1
+arg:greedy
 arg:1
 arg:1
@@ -77,5 +77,5 @@
 TESTNAME:distances weight hungarian
 arg:similarity.gen
-arg:0
+arg:hungarian
 arg:0
 arg:0
@@ -88,5 +88,5 @@
 TESTNAME:all weights hungarian
 arg:similarity.gen
-arg:0
+arg:hungarian
 arg:1
 arg:1
@@ -99,5 +99,5 @@
 TESTNAME:all weights fixed z hungarian
 arg:similarity.gen
-arg:0
+arg:hungarian
 arg:1
 arg:1
@@ -107,2 +107,11 @@
 out:*INSERTPLATFORMDEPENDENTFILE*:similarity_goals/all_weights_fixed_z_hungarian
 RUNTEST
+
+TESTNAME:distribution
+arg:similarity.gen
+arg:distribution
+arg:5
+arg:128
+arg:100000
+out:*INSERTPLATFORMDEPENDENTFILE*:similarity_goals/distribution
+RUNTEST
Index: /cpp/tests/similarity_goals/distribution.goal
===================================================================
--- /cpp/tests/similarity_goals/distribution.goal	(revision 1044)
+++ /cpp/tests/similarity_goals/distribution.goal	(revision 1044)
@@ -0,0 +1,6 @@
+0.00	0.42	0.37	0.33	0.95	
+0.41	0.00	0.73	0.27	1.32	
+0.37	0.73	0.00	0.70	0.59	
+0.33	0.27	0.70	0.00	1.28	
+0.96	1.32	0.57	1.28	0.01	
+
