source: cpp/frams/model/similarity/simil_model.cpp @ 356

Last change on this file since 356 was 356, checked in by Maciej Komosinski, 10 years ago

Changed default values for weights

  • Property svn:eol-style set to native
File size: 76.7 KB
Line 
1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
2// Copyright (C) 1999-2015  Maciej Komosinski and Szymon Ulatowski.
3// See LICENSE.txt for details.
4
5// simil_model.cpp: implementation of the ModelSimil class.
6//
7//////////////////////////////////////////////////////////////////////
8#include "SVD/matrix_tools.h"
9#include "simil_model.h"
10#include "simil_match.h"
11#include "frams/model/modelparts.h"
12#include "frams/util/list.h"
13#include "common/nonstd.h"
14#include <frams/vm/classes/genoobj.h>
15#include <stdlib.h>
16#include <math.h>
17#include <string>
18#include <limits>
19#include <assert.h>
20#include <vector>
21#include <algorithm>
22
23#define DB(x)  //define as x if you want to print debug information
24
25const int ModelSimil::iNOFactors = 4;
26//depth of the fuzzy neighbourhood
27int fuzDepth = 0;
28
29#define FIELDSTRUCT ModelSimil
30
31static ParamEntry MSparam_tab[] = {
32    {"Genetics: Similarity", 1, 5,"ModelSimilarity"},
33    {"simil_parts", 0, 0, "Weight of parts count", "f 0 100 0", FIELD(m_adFactors[0]), "",},
34    {"simil_partdeg", 0, 0, "Weight of parts' degree", "f 0 100 1", FIELD(m_adFactors[1]), "",},
35    {"simil_neuro", 0, 0, "Weight of neurons count", "f 0 100 0.1", FIELD(m_adFactors[2]), "",},
36    {"simil_partgeom", 0, 0, "Weight of parts' geometric distances", "f 0 100 0", FIELD(m_adFactors[3]), "",},
37    {"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.",},
38    {0,},
39};
40
41#undef FIELDSTRUCT
42
43//////////////////////////////////////////////////////////////////////
44// Construction/Destruction
45//////////////////////////////////////////////////////////////////////
46
47/** Constructor. Sets default weights. Initializes other fields with zeros.
48 */
49ModelSimil::ModelSimil() : localpar(MSparam_tab, this), m_iDV(0), m_iDD(0), m_iDN(0), m_dDG(0.0)
50{
51    // weights for the similarty formula
52    m_adFactors[0] = 0;
53    m_adFactors[1] = 1;
54    m_adFactors[2] = 0.1;
55    m_adFactors[3] = 0;
56
57    m_Gen[0] = NULL;
58    m_Gen[1] = NULL;
59    m_Mod[0] = NULL;
60    m_Mod[1] = NULL;
61    m_aDegrees[0] = NULL;
62    m_aDegrees[1] = NULL;
63    m_aPositions[0] = NULL;
64    m_aPositions[1] = NULL;
65    m_fuzzyNeighb[0] = NULL;
66    m_fuzzyNeighb[1] = NULL;
67    m_Neighbours[0] = NULL;
68    m_Neighbours[1] = NULL;
69    m_pMatching = NULL;
70
71    //determines wheter "fuzzy vertex degree" should be used
72    //currently "fuzzy vertex degree" is inactive
73    isFuzzy = 0;
74    fuzzyDepth = 10;
75}
76
77/**     Evaluates distance between two given genotypes. The distance depends strongly
78    on weights set.
79        @param G0 Pointer to the first of compared genotypes
80        @param G1 Pointer to the second of compared genotypes.
81        @return Distance between two genotypes.
82    @sa m_adFactors, matching_method
83 */
84double ModelSimil::EvaluateDistance(const Geno *G0, const Geno *G1)
85{
86    double dResult = 0;
87
88    m_Gen[0] = G0;
89    m_Gen[1] = G1;
90
91    // check whether pointers are not NULL
92    if (m_Gen[0] == NULL || m_Gen[1] == NULL)
93    {
94        DB(printf("ModelSimil::EvaluateDistance - invalid genotypes pointers\n");)
95        return 0.0;
96    }
97    // create models of objects to compare
98    m_Mod[0] = new Model(*(m_Gen[0]));
99    m_Mod[1] = new Model(*(m_Gen[1]));
100
101    // validate models
102    if (m_Mod[0] == NULL || m_Mod[1] == NULL || !(m_Mod[0]->isValid()) || !(m_Mod[1]->isValid()))
103    {
104        DB(printf("ModelSimil::EvaluateDistance - invalid models pointers\n");)
105        return 0.0;
106    }
107
108    // difference in the number of vertices (Parts) - positive
109    // find object that has less parts (m_iSmaller)
110    m_iDV = (m_Mod[0]->getPartCount() - m_Mod[1]->getPartCount());
111    if (m_iDV > 0)
112        m_iSmaller = 1;
113    else
114    {
115        m_iSmaller = 0;
116        m_iDV = -m_iDV;
117    }
118
119    // check if index of the smaller organism is a valid index
120    assert((m_iSmaller == 0) || (m_iSmaller == 1));
121    // validate difference in the parts number
122    assert(m_iDV >= 0);
123
124    // create Parts matching object
125    m_pMatching = new SimilMatching(m_Mod[ 0 ]->getPartCount(), m_Mod[ 1 ]->getPartCount());
126    // validate matching object
127    assert(m_pMatching != NULL);
128    assert(m_pMatching->IsEmpty() == true);
129
130
131    // assign matching function
132    int (ModelSimil::* pfMatchingFunction) () = NULL;
133
134    pfMatchingFunction = &ModelSimil::MatchPartsGeometry;
135
136    // match Parts (vertices of creatures)
137    if ((this->*pfMatchingFunction)() == 0)
138    {
139        DB(printf("ModelSimil::EvaluateDistance - MatchParts() error\n");)
140        return 0.0;
141    }
142
143    // after matching function call we must have full matching
144    assert(m_pMatching->IsFull() == true);
145   
146    DB(SaveIntermediateFiles();)
147           
148    // count differences in matched parts
149    if (CountPartsDistance() == 0)
150    {
151        DB(printf("ModelSimil::EvaluateDistance - CountPartDistance() error\n");)
152        return 0.0;
153    }
154
155    // delete degree arrays created in CreatePartInfoTables
156    SAFEDELETEARRAY(m_aDegrees[0]);
157    SAFEDELETEARRAY(m_aDegrees[1]);
158
159    // and position arrays
160    SAFEDELETEARRAY(m_aPositions[0]);
161    SAFEDELETEARRAY(m_aPositions[1]);
162
163    // in fuzzy mode delete arrays of neighbourhood and fuzzy neighbourhood
164    if (isFuzzy)
165    {
166        for (int i = 0; i != 2; ++i)
167        {
168            for (int j = 0; j != m_Mod[i]->getPartCount(); ++j)
169            {
170                delete[] m_Neighbours[i][j];
171                delete[] m_fuzzyNeighb[i][j];
172            }
173            delete[] m_Neighbours[i];
174            delete[] m_fuzzyNeighb[i];
175        }
176
177    }
178   
179    // delete created models
180    SAFEDELETE(m_Mod[0]);
181    SAFEDELETE(m_Mod[1]);
182
183    // delete created matching
184    SAFEDELETE(m_pMatching);
185
186    dResult = m_adFactors[0] * double(m_iDV) +
187            m_adFactors[1] * double(m_iDD) +
188            m_adFactors[2] * double(m_iDN) +
189            m_adFactors[3] * double(m_dDG);
190
191    return dResult;
192}
193
194ModelSimil::~ModelSimil()
195{
196    // matching should have been deleted earlier
197    assert(m_pMatching == NULL);
198}
199
200/**     Creates files matching.txt, org0.txt and org1.txt containing information
201 * about the matching and both organisms for visualization purpose.
202 */
203void ModelSimil::SaveIntermediateFiles()
204{
205    assert(m_pMatching->IsFull() == true);
206    printf("Saving the matching to file 'matching.txt'\n");
207    FILE *pMatchingFile = NULL;
208    // try to open the file
209    pMatchingFile = fopen("matching.txt", "wt");
210    assert(pMatchingFile != NULL);
211
212    int iOrgPart; // original index of a Part
213    int nBigger; // index of the larger organism
214
215    // check which object is bigger
216    if (m_pMatching->GetObjectSize(0) >= m_pMatching->GetObjectSize(1))
217    {
218        nBigger = 0;
219    }
220    else
221    {
222        nBigger = 1;
223    }
224
225    // print first line - original indices of Parts of the bigger organism
226    fprintf(pMatchingFile, "[ ");
227    for (iOrgPart = 0; iOrgPart < m_pMatching->GetObjectSize(nBigger); iOrgPart++)
228    {
229        fprintf(pMatchingFile, "%2i ", iOrgPart);
230    }
231    fprintf(pMatchingFile, "] : ORG[%i]\n", nBigger);
232
233    // print second line - matched original indices of the second organism
234    fprintf(pMatchingFile, "[ ");
235    for (iOrgPart = 0; iOrgPart < m_pMatching->GetObjectSize(nBigger); iOrgPart++)
236    {
237        int iSorted; // index of the iOrgPart after sorting (as used by matching)
238        int iSortedMatched; // index of the matched Part (after sorting)
239        int iOrginalMatched; // index of the matched Part (the original one)
240
241        // find the index of iOrgPart after sorting (in m_aDegrees)
242        for (iSorted = 0; iSorted < m_Mod[ nBigger ]->getPartCount(); iSorted++)
243        {
244            // for each iSorted, an index in the sorted m_aDegrees array
245            if (m_aDegrees[ nBigger ][ iSorted ][ 0 ] == iOrgPart)
246            {
247                // if the iSorted Part is the one with iOrgPart as the orginal index
248                // remember the index
249                break;
250            }
251        }
252        // if the index iSorted was found, then this condition is met
253        assert(iSorted < m_Mod[ nBigger ]->getPartCount());
254
255        // find the matched sorted index
256        if (m_pMatching->IsMatched(nBigger, iSorted))
257        {
258            // if Part iOrgPart is matched
259            // then get the matched Part (sorted) index
260            iSortedMatched = m_pMatching->GetMatchedIndex(nBigger, iSorted);
261            assert(iSortedMatched >= 0);
262            // and find its original index
263            iOrginalMatched = m_aDegrees[ 1 - nBigger ][ iSortedMatched ][ 0 ];
264            fprintf(pMatchingFile, "%2i ", iOrginalMatched);
265        }
266        else
267        {
268            // if the Part iOrgPart is not matched
269            // just print "X"
270            fprintf(pMatchingFile, " X ");
271        }
272    } // for ( iOrgPart )
273
274    // now all matched Part indices are printed out, end the line
275    fprintf(pMatchingFile, "] : ORG[%i]\n", 1 - nBigger);
276
277    // close the file
278    fclose(pMatchingFile);
279    // END TEMP
280
281    // TEMP
282    // print out the 2D positions of Parts of both of the organisms
283    // to files "org0.txt" and "org1.txt" using the original indices of Parts
284    int iModel; // index of a model (an organism)
285    FILE *pModelFile;
286    for (iModel = 0; iModel < 2; iModel++)
287    {
288        // for each iModel, a model of a compared organism
289        // write its (only 2D) positions to a file "org<iModel>.txt"
290        // construct the model filename "org<iModel>.txt"
291        std::string sModelFilename("org");
292        //              char *szModelIndex = "0"; // the index of the model (iModel) in the character form
293        char szModelIndex[2];
294        sprintf(szModelIndex, "%i", iModel);
295        sModelFilename += szModelIndex;
296        sModelFilename += ".txt";
297        // open the file for writing
298        pModelFile = fopen(sModelFilename.c_str(), "wt"); //FOPEN_WRITE
299        assert(pModelFile != NULL);
300        // write the 2D positions of iModel to the file
301        int iOriginalPart; // an original index of a Part
302        for (iOriginalPart = 0; iOriginalPart < m_Mod[ iModel ]->getPartCount(); iOriginalPart++)
303        {
304            // for each iOriginalPart, a Part of the organism iModel
305            // get the 2D coordinates of the Part
306            double dPartX = m_aPositions[ iModel ][ iOriginalPart ].x;
307            double dPartY = m_aPositions[ iModel ][ iOriginalPart ].y;
308            // print the line: <iOriginalPart> <dPartX> <dPartY>
309            fprintf(pModelFile, "%i %.4lf %.4lf\n", iOriginalPart, dPartX, dPartY);
310        }
311        // close the file
312        fclose(pModelFile);
313    }
314}
315
316/** Comparison function required for qsort() call. Used while sorting groups of
317    Parts with respect to degree. Compares two TDN structures
318    with respect to their [1] field (degree). Highest degree goes first.
319    @param pElem1 Pointer to the TDN structure of some Part.
320    @param pElem2 Pointer to the TDN structure of some Part.
321    @return (-1) - pElem1 should go first, 0 - equal, (1) - pElem2 should go first.
322 */
323int ModelSimil::CompareDegrees(const void *pElem1, const void *pElem2)
324{
325    int *tdn1 = (int *) pElem1;
326    int *tdn2 = (int *) pElem2;
327
328    if (tdn1[1] > tdn2[1])
329    {
330        // when degree - tdn1[1] - is BIGGER
331        return -1;
332    }
333    else
334        if (tdn1[1] < tdn2[1])
335    {
336        // when degree - tdn2[1] - is BIGGER
337        return 1;
338    }
339    else
340    {
341        return 0;
342    }
343}
344
345/** Comparison function required for qsort() call. Used while sorting groups of Parts with
346        the same degree. Firstly, compare NIt. Secondly, compare Neu. If both are equal -
347        compare Parts' original index (they are never equal). So this sorting assures
348        that the order obtained is deterministic.
349    @param pElem1 Pointer to the TDN structure of some Part.
350    @param pElem2 Pointer to the TDN structure of some Part.
351    @return (-1) - pElem1 should go first, 0 - equal, (1) - pElem2 should go first.
352 */
353int ModelSimil::CompareConnsNo(const void *pElem1, const void *pElem2)
354{
355    // pointers to TDN arrays
356    int *tdn1, *tdn2;
357    // definitions of elements being compared
358    tdn1 = (int *) pElem1;
359    tdn2 = (int *) pElem2;
360
361    // comparison according to Neural Connections (to jest TDN[2])
362    if (tdn1[NEURO_CONNS] > tdn1[NEURO_CONNS])
363    {
364        // when number of NConn Elem1 is BIGGER
365        return -1;
366    }
367    else
368        if (tdn1[NEURO_CONNS] < tdn1[NEURO_CONNS])
369    {
370        // when number of NConn Elem1 is SMALLER
371        return 1;
372    }
373    else
374    {
375        // when numbers of NConn are EQUAL
376        // compare Neu numbers (TDN[3])
377        if (tdn1[NEURONS] > tdn2[NEURONS])
378        {
379            // when number of Neu is BIGGER for Elem1
380            return -1;
381        }
382        else
383            if (tdn1[NEURONS] < tdn2[NEURONS])
384        {
385            // when number of Neu is SMALLER for Elem1
386            return 1;
387        }
388        else
389        {
390            // when numbers of Nconn and Neu are equal we check original indices
391            // of Parts being compared
392
393            // comparison according to OrgIndex
394            if (tdn1[ORIG_IND] > tdn2[ORIG_IND])
395            {
396                // when the number of NIt Deg1 id BIGGER
397                return -1;
398            }
399            else
400                if (tdn1[ORIG_IND] < tdn2[ORIG_IND])
401            {
402                // when the number of NIt Deg1 id SMALLER
403                return 1;
404            }
405            else
406            {
407                // impossible, indices are alway different
408                return 0;
409            }
410        }
411    }
412}
413
414/** Returns number of factors involved in final distance computation.
415        These factors include differences in numbers of parts, degrees,
416        number of neurons.
417 */
418int ModelSimil::GetNOFactors()
419{
420    return ModelSimil::iNOFactors;
421}
422
423/** Prints the array of degrees for the given organism. Debug method.
424 */
425void ModelSimil::_PrintDegrees(int i)
426{
427    int j;
428    printf("Organizm %i :", i);
429    printf("\n      ");
430    for (j = 0; j < m_Mod[i]->getPartCount(); j++)
431        printf("%3i ", j);
432    printf("\nInd:  ");
433    for (j = 0; j < m_Mod[i]->getPartCount(); j++)
434        printf("%3i ", (int) m_aDegrees[i][j][0]);
435    printf("\nDeg:  ");
436    for (j = 0; j < m_Mod[i]->getPartCount(); j++)
437        printf("%3i ", (int) m_aDegrees[i][j][1]);
438    printf("\nNIt:  ");
439    for (j = 0; j < m_Mod[i]->getPartCount(); j++)
440        printf("%3i ", (int) m_aDegrees[i][j][2]);
441    printf("\nNeu:  ");
442    for (j = 0; j < m_Mod[i]->getPartCount(); j++)
443        printf("%3i ", (int) m_aDegrees[i][j][3]);
444    printf("\n");
445}
446
447/** Prints one array of ints. Debug method.
448    @param array Base pointer of the array.
449    @param base First index of the array's element.
450    @param size Number of elements to print.
451 */
452void ModelSimil::_PrintArray(int *array, int base, int size)
453{
454    int i;
455    for (i = base; i < base + size; i++)
456    {
457        printf("%i ", array[i]);
458    }
459    printf("\n");
460}
461
462void ModelSimil::_PrintArrayDouble(double *array, int base, int size)
463{
464    int i;
465    for (i = base; i < base + size; i++)
466    {
467        printf("%f ", array[i]);
468    }
469    printf("\n");
470}
471
472/** Prints one array of parts neighbourhood.
473    @param index of organism
474 */
475void ModelSimil::_PrintNeighbourhood(int o)
476{
477    assert(m_Neighbours[o] != 0);
478    printf("Neighbourhhod of organism %i\n", o);
479    int size = m_Mod[o]->getPartCount();
480    for (int i = 0; i < size; i++)
481    {
482        for (int j = 0; j < size; j++)
483        {
484            printf("%i ", m_Neighbours[o][i][j]);
485        }
486        printf("\n");
487    }
488}
489
490/** Creates arrays holding information about organisms' Parts (m_aDegrees) andm_Neigh
491    fills them with initial data (original indices and zeros).
492    Assumptions:
493    - Models (m_Mod) are created and available.
494 */
495int ModelSimil::CreatePartInfoTables()
496{
497    // check assumptions about models
498    assert((m_Mod[0] != NULL) && (m_Mod[1] != NULL));
499    assert(m_Mod[0]->isValid() && m_Mod[1]->isValid());
500
501    int i, j, partCount;
502    // utwórz tablice na informacje o stopniach wierzchołków i liczbie neuroitems
503    for (i = 0; i < 2; i++)
504    {
505        partCount = m_Mod[i]->getPartCount();
506        // utworz i wypelnij tablice dla Parts wartosciami poczatkowymi
507        m_aDegrees[i] = new TDN[ partCount ];
508
509        if (isFuzzy)
510        {
511            m_Neighbours[i] = new int*[ partCount ];
512            m_fuzzyNeighb[i] = new float*[ partCount];
513        }
514
515        if (m_aDegrees[i] != NULL && (isFuzzy != 1 || (m_Neighbours[i] != NULL && m_fuzzyNeighb[i] != NULL)))
516        {
517            // wypelnij tablice zgodnie z sensem TDN[0] - orginalny index
518            // TDN[1], TDN[2], TDN[3] - zerami
519            DB(printf("m_aDegrees[%i]: %p\n", i, m_aDegrees[i]);)
520            for (j = 0; j < partCount; j++)
521            {
522                m_aDegrees[i][j][0] = j;
523                m_aDegrees[i][j][1] = 0;
524                m_aDegrees[i][j][2] = 0;
525                m_aDegrees[i][j][3] = 0;
526                m_aDegrees[i][j][4] = 0;
527
528                // sprawdz, czy nie piszemy po jakims szalonym miejscu pamieci
529                assert(m_aDegrees[i][j] != NULL);
530
531                if (isFuzzy)
532                {
533                    m_Neighbours[i][j] = new int[partCount];
534                    for (int k = 0; k < partCount; k++)
535                    {
536                        m_Neighbours[i][j][k] = 0;
537                    }
538
539                    m_fuzzyNeighb[i][j] = new float[fuzzyDepth];
540                    for (int k = 0; k < fuzzyDepth; k++)
541                    {
542                        m_fuzzyNeighb[i][j][k] = 0;
543                    }
544
545                    assert(m_Neighbours[i][j] != NULL);
546                    assert(m_fuzzyNeighb[i][j] != NULL);
547                }
548
549            }
550        }
551        else
552        {
553            DB(printf("ModelSimil::EvaluateDistance - nie ma pamieci na Degrees\n");)
554            return 0;
555        }
556        // utworz tablice dla pozycji 3D Parts (wielkosc tablicy: liczba Parts organizmu)
557        m_aPositions[ i ] = new Pt3D[ m_Mod[i]->getPartCount() ];
558        assert(m_aPositions[ i ] != NULL);
559        // wypelnij tablice OnJoints i Anywhere wartościami początkowymi
560        // OnJoint
561        m_aOnJoint[i][0] = 0;
562        m_aOnJoint[i][1] = 0;
563        m_aOnJoint[i][2] = 0;
564        m_aOnJoint[i][3] = 0;
565        // Anywhere
566        m_aAnywhere[i][0] = 0;
567        m_aAnywhere[i][1] = 0;
568        m_aAnywhere[i][2] = 0;
569        m_aAnywhere[i][3] = 0;
570    }
571    return 1;
572}
573
574/** Computes degrees of Parts of both organisms. Fills in the m_aDegrees arrays
575    with proper information about degrees.
576    Assumptions:
577    - Models (m_Mod) are created and available.
578    - Arrays m_aDegrees are created.
579 */
580int ModelSimil::CountPartDegrees()
581{
582    // sprawdz zalozenie - o modelach
583    assert((m_Mod[0] != NULL) && (m_Mod[1] != NULL));
584    assert(m_Mod[0]->isValid() && m_Mod[1]->isValid());
585
586    // sprawdz zalozenie - o tablicach
587    assert(m_aDegrees[0] != NULL);
588    assert(m_aDegrees[1] != NULL);
589
590    Part *P1, *P2;
591    int i, j, i1, i2;
592
593    // dla obu stworzen oblicz stopnie wierzcholkow
594    for (i = 0; i < 2; i++)
595    {
596        // dla wszystkich jointow
597        for (j = 0; j < m_Mod[i]->getJointCount(); j++)
598        {
599            // pobierz kolejny Joint
600            Joint *J = m_Mod[i]->getJoint(j);
601            // wez jego konce
602            P1 = J->part1;
603            P2 = J->part2;
604            // znajdz ich indeksy w Modelu (indeksy orginalne)
605            i1 = m_Mod[i]->findPart(P1);
606            i2 = m_Mod[i]->findPart(P2);
607            // zwieksz stopien odpowiednich Parts
608            m_aDegrees[i][i1][DEGREE]++;
609            m_aDegrees[i][i2][DEGREE]++;
610            m_aDegrees[i][i1][FUZZ_DEG]++;
611            m_aDegrees[i][i2][FUZZ_DEG]++;
612            if (isFuzzy)
613            {
614                m_Neighbours[i][i1][i2] = 1;
615                m_Neighbours[i][i2][i1] = 1;
616            }
617        }
618        // dla elementow nie osadzonych na Parts (OnJoint, Anywhere) -
619        // stopnie wierzchołka są już ustalone na zero
620    }
621
622    if (isFuzzy)
623    {
624        CountFuzzyNeighb();
625    }
626
627    return 1;
628}
629
630void ModelSimil::GetNeighbIndexes(int mod, int partInd, std::vector<int> &indexes)
631{
632    indexes.clear();
633    int i, size = m_Mod[mod]->getPartCount();
634
635    for (i = 0; i < size; i++)
636    {
637        if (m_Neighbours[mod][partInd][i] > 0)
638        {
639            indexes.push_back(i);
640        }
641    }
642}
643
644int cmpFuzzyRows(const void *pa, const void *pb)
645{
646    float **a = (float**) pa;
647    float **b = (float**) pb;
648
649
650    for (int i = 1; i < fuzDepth; i++)
651    {
652        if (a[0][i] > b[0][i])
653        {
654
655            return -1;
656        }
657        if (a[0][i] < b[0][i])
658        {
659
660            return 1;
661        }
662    }
663
664    return 0;
665}
666
667//store information about identity of parts "fuzzy degrees" in the m_aDegrees[4]
668void ModelSimil::CheckFuzzyIdentity()
669{
670    int partCount = 0;
671    for (int mod = 0; mod < 2; mod++)
672    {
673        //for subsequent pairs of parts
674        partCount = m_Mod[mod]->getPartCount();
675        m_aDegrees[mod][partCount - 1][FUZZ_DEG] = 0;
676        for (int partInd = (partCount - 2); partInd >= 0; partInd--)
677        {
678            m_aDegrees[mod][partInd][FUZZ_DEG] = m_aDegrees[mod][partInd + 1][FUZZ_DEG];
679            for (int depth = 1; depth < fuzzyDepth; depth++)
680            {
681                if (m_fuzzyNeighb[mod][partInd][depth] != m_fuzzyNeighb[mod][partInd + 1][depth])
682                {
683                    m_aDegrees[mod][partInd][FUZZ_DEG] += 1;
684                    break;
685                }
686            }
687        }
688    }
689}
690
691//sort according to fuzzy degree
692void ModelSimil::SortFuzzyNeighb()
693{
694    fuzDepth = fuzzyDepth;
695    for (int mod = 0; mod < 2; mod++)
696    {
697        std::qsort(m_fuzzyNeighb[mod], (size_t) m_Mod[mod]->getPartCount(), sizeof (m_fuzzyNeighb[mod][0]), cmpFuzzyRows);
698    }
699}
700
701//computes fuzzy vertex degree
702void ModelSimil::CountFuzzyNeighb()
703{
704    assert(m_aDegrees[0] != NULL);
705    assert(m_aDegrees[1] != NULL);
706
707    assert(m_Neighbours[0] != NULL);
708    assert(m_Neighbours[1] != NULL);
709
710    assert(m_fuzzyNeighb[0] != NULL);
711    assert(m_fuzzyNeighb[1] != NULL);
712
713    std::vector<int> nIndexes;
714    float newDeg = 0;
715
716    for (int mod = 0; mod < 2; mod++)
717    {
718        int partCount = m_Mod[mod]->getPartCount();
719
720        for (int depth = 0; depth < fuzzyDepth; depth++)
721        {
722            //use first column for storing indices
723            for (int partInd = 0; partInd < partCount; partInd++)
724            {
725                if (depth == 0)
726                {
727                    m_fuzzyNeighb[mod][partInd][depth] = partInd;
728                }
729                else if (depth == 1)
730                {
731                    m_fuzzyNeighb[mod][partInd][depth] = m_aDegrees[mod][partInd][DEGREE];
732                }
733                else
734                {
735                    GetNeighbIndexes(mod, partInd, nIndexes);
736                    for (int k = 0; k < (int) nIndexes.size(); k++)
737                    {
738                        newDeg += m_fuzzyNeighb[mod][nIndexes.at(k)][depth - 1];
739                    }
740                    newDeg /= nIndexes.size();
741                    m_fuzzyNeighb[mod][partInd][depth] = newDeg;
742                    for (int mod = 0; mod < 2; mod++)
743                    {
744                        int partCount = m_Mod[mod]->getPartCount();
745                        for (int i = partCount - 1; i >= 0; i--)
746                        {
747
748                        }
749                    }
750                    newDeg = 0;
751                }
752            }
753        }
754    }
755
756    SortFuzzyNeighb();
757}
758
759/** Gets information about Parts' positions in 3D from models into the arrays
760        m_aPositions.
761    Assumptions:
762    - Models (m_Mod) are created and available.
763    - Arrays m_aPositions are created.
764    @return 1 if success, otherwise 0.
765 */
766int ModelSimil::GetPartPositions()
767{
768    // sprawdz zalozenie - o modelach
769    assert((m_Mod[0] != NULL) && (m_Mod[1] != NULL));
770    assert(m_Mod[0]->isValid() && m_Mod[1]->isValid());
771
772    // sprawdz zalozenie - o tablicach m_aPositions
773    assert(m_aPositions[0] != NULL);
774    assert(m_aPositions[1] != NULL);
775
776    // dla każdego stworzenia skopiuj informację o polozeniu jego Parts
777    // do tablic m_aPositions
778    Part *pPart;
779    int iMod; // licznik modeli (organizmow)
780    int iPart; // licznik Parts
781    for (iMod = 0; iMod < 2; iMod++)
782    {
783        // dla każdego z modeli iMod
784        for (iPart = 0; iPart < m_Mod[ iMod ]->getPartCount(); iPart++)
785        {
786            // dla każdego iPart organizmu iMod
787            // pobierz tego Part
788            pPart = m_Mod[ iMod ]->getPart(iPart);
789            // zapamietaj jego pozycje 3D w tablicy m_aPositions
790            m_aPositions[ iMod ][ iPart ].x = pPart->p.x;
791            m_aPositions[ iMod ][ iPart ].y = pPart->p.y;
792            m_aPositions[ iMod ][ iPart ].z = pPart->p.z;
793        }
794    }
795
796    return 1;
797}
798
799/** Computes numbers of neurons and neurons' inputs for each Part of each
800    organisms and fills in the m_aDegrees array.
801    Assumptions:
802    - Models (m_Mod) are created and available.
803    - Arrays m_aDegrees are created.
804 */
805int ModelSimil::CountPartNeurons()
806{
807    // sprawdz zalozenie - o modelach
808    assert((m_Mod[0] != NULL) && (m_Mod[1] != NULL));
809    assert(m_Mod[0]->isValid() && m_Mod[1]->isValid());
810
811    // sprawdz zalozenie - o tablicach
812    assert(m_aDegrees[0] != NULL);
813    assert(m_aDegrees[1] != NULL);
814
815    Part *P1;
816    Joint *J1;
817    int i, j, i2, neuro_connections;
818
819    // dla obu stworzen oblicz liczbe Neurons + connections dla Parts
820    // a takze dla OnJoints i Anywhere
821    for (i = 0; i < 2; i++)
822    {
823        for (j = 0; j < m_Mod[i]->getNeuroCount(); j++)
824        {
825            // pobierz kolejny Neuron
826            Neuro *N = m_Mod[i]->getNeuro(j);
827            // policz liczbe jego wejść i jego samego tez
828            // czy warto w ogole liczyc polaczenia...? co to da/spowoduje?
829            neuro_connections = N->getInputCount() + 1;
830            // wez Part, na ktorym jest Neuron
831            P1 = N->getPart();
832            if (P1)
833            {
834                // dla neuronow osadzonych na Partach
835                i2 = m_Mod[i]->findPart(P1); // znajdz indeks Part w Modelu
836                m_aDegrees[i][i2][2] += neuro_connections; // zwieksz liczbe Connections+Neurons dla tego Part (TDN[2])
837                m_aDegrees[i][i2][3]++; // zwieksz liczbe Neurons dla tego Part (TDN[3])
838            }
839            else
840            {
841                // dla neuronow nie osadzonych na partach
842                J1 = N->getJoint();
843                if (J1)
844                {
845                    // dla tych na Jointach
846                    m_aOnJoint[i][2] += neuro_connections; // zwieksz liczbe Connections+Neurons
847                    m_aOnJoint[i][3]++; // zwieksz liczbe Neurons
848                }
849                else
850                {
851                    // dla tych "gdziekolwiek"
852                    m_aAnywhere[i][2] += neuro_connections; // zwieksz liczbe Connections+Neurons
853                    m_aAnywhere[i][3]++; // zwieksz liczbe Neurons
854                }
855            }
856        }
857    }
858    return 1;
859}
860
861/** Sorts arrays m_aDegrees (for each organism) by Part's degree, and then by
862    number of neural connections and neurons in groups of Parts with the same
863    degree.
864    Assumptions:
865    - Models (m_Mod) are created and available.
866    - Arrays m_aDegrees are created.
867    @saeDegrees, CompareItemNo
868 */
869int ModelSimil::SortPartInfoTables()
870{
871    // sprawdz zalozenie - o modelach
872    assert((m_Mod[0] != NULL) && (m_Mod[1] != NULL));
873    assert(m_Mod[0]->isValid() && m_Mod[1]->isValid());
874
875    // sprawdz zalozenie - o tablicach
876    assert(m_aDegrees[0] != NULL);
877    assert(m_aDegrees[1] != NULL);
878
879    int i;
880    // sortowanie obu tablic wg stopni punktów - TDN[1]
881    if (isFuzzy != 1)
882    {
883        for (i = 0; i < 2; i++)
884        {
885            DB(_PrintDegrees(i));
886            std::qsort(m_aDegrees[i], (size_t) (m_Mod[i]->getPartCount()),
887                       sizeof (TDN), ModelSimil::CompareDegrees);
888            DB(_PrintDegrees(i));
889        }
890    }//sortowanie wg romzmytego stopnia wierzcholka
891
892    else
893    {
894        SortPartInfoFuzzy();
895    }
896
897
898    // sprawdzenie wartosci parametru
899    DB(i = sizeof (TDN);)
900            int degreeType = (isFuzzy == 1) ? FUZZ_DEG : DEGREE;
901
902    // sortowanie obu tablic m_aDegrees wedlug liczby neuronów i
903    // czesci neuronu - ale w obrebie grup o tym samym stopniu
904    for (i = 0; i < 2; i++)
905    {
906        int iPocz = 0;
907        int iDeg, iNewDeg, iPartCount, j;
908        // stopien pierwszego punktu w tablicy Degrees  odniesienie
909        iDeg = m_aDegrees[i][0][degreeType];
910        iPartCount = m_Mod[i]->getPartCount();
911        // po kolei dla kazdego punktu w organizmie
912        for (j = 0; j <= iPartCount; j++)
913        {
914            // sprawdz stopien punktu (lub nadaj 0 - gdy juz koniec tablicy)
915            //                  iNewDeg = (j != iPartCount) ? m_aDegrees[i][j][1] : 0;
916            // usunieto stara wersje porownania!!! wprowadzono znak porownania <
917
918            iNewDeg = (j < iPartCount) ? m_aDegrees[i][j][degreeType] : 0;
919            // skoro tablice sa posortowane wg stopni, to mamy na pewno taka kolejnosc
920            assert(iNewDeg <= iDeg);
921            if (iNewDeg != iDeg)
922            {
923                // gdy znaleziono koniec grupy o tym samym stopniu
924                // sortuj po liczbie neuronow w obrebie grupy
925                DB(_PrintDegrees(i));
926                DB(printf("qsort( poczatek=%i, rozmiar=%i, sizeof(TDN)=%i)\n", iPocz, (j - iPocz), sizeof (TDN));)
927                // wyswietlamy z jedna komorka po zakonczeniu tablicy
928                DB(_PrintArray(m_aDegrees[i][iPocz], 0, (j - iPocz)*4);)
929
930                std::qsort(m_aDegrees[i][iPocz], (size_t) (j - iPocz),
931                           sizeof (TDN), ModelSimil::CompareConnsNo);
932                DB(_PrintDegrees(i));
933                // wyswietlamy z jedna komorka po zakonczeniu tablicy
934                DB(_PrintArray(m_aDegrees[i][iPocz], 0, (j - iPocz)*4);)
935                // rozpocznij nowa grupe
936                iPocz = j;
937                iDeg = iNewDeg;
938            }
939        }
940    }
941    return 1;
942}
943
944int ModelSimil::SortPartInfoFuzzy()
945{
946
947    // sprawdz zalozenie - o modelach
948    assert((m_Mod[0] != NULL) && (m_Mod[1] != NULL));
949    assert(m_Mod[0]->isValid() && m_Mod[1]->isValid());
950
951    // sprawdz zalozenie - o tablicach
952    assert(m_aDegrees[0] != NULL);
953    assert(m_aDegrees[1] != NULL);
954    // sprawdz zalozenie - o tablicach
955    assert(m_fuzzyNeighb[0] != NULL);
956    assert(m_fuzzyNeighb[1] != NULL);
957
958
959    TDN * m_aDegreesTmp[2];
960
961    for (int i = 0; i < 2; i++)
962    {
963        int partCount = m_Mod[i]->getPartCount();
964        m_aDegreesTmp[i] = new TDN[ partCount ];
965
966        for (int j = 0; j < partCount; j++)
967        {
968            for (int k = 0; k < TDN_SIZE; k++)
969            {
970                m_aDegreesTmp[i][j][k] = m_aDegrees[i][j][k];
971            }
972        }
973    }
974
975    int newInd = 0;
976    for (int i = 0; i < 2; i++)
977    {
978        int partCount = m_Mod[i]->getPartCount();
979        for (int j = 0; j < partCount; j++)
980        {
981            newInd = (int) m_fuzzyNeighb[i][j][0];
982            for (int k = 0; k < TDN_SIZE; k++)
983            {
984                m_aDegrees[i][j][k] = m_aDegreesTmp[i][newInd][k];
985            }
986        }
987    }
988
989    SAFEDELETEARRAY(m_aDegreesTmp[0]);
990    SAFEDELETEARRAY(m_aDegreesTmp[1]);
991
992    CheckFuzzyIdentity();
993
994    return 1;
995}
996
997/** Checks if given Parts have identical physical and biological properties
998    (except for geometry that might differ).
999    @param P1 Pointer to first Part.
1000    @param P2 Pointer to second Part.
1001    @return 1 - identical properties, 0 - there are differences.
1002 */
1003int ModelSimil::CheckPartsIdentity(Part *P1, Part *P2)
1004{
1005    // sprawdz, czy te Parts chociaz sa w sensownym miejscu pamieci
1006    assert((P1 != NULL) && (P2 != NULL));
1007
1008    if ((P1->assim != P2->assim) ||
1009            (P1->friction != P2->friction) ||
1010            (P1->ingest != P2->ingest) ||
1011            (P1->mass != P2->mass) ||
1012            (P1->size != P2->size) ||
1013            (P1->density != P2->density))
1014        // gdy znaleziono jakas roznice w parametrach fizycznych i
1015        // biologicznych
1016        return 0;
1017    else
1018        // gdy nie ma roznic
1019        return 1;
1020}
1021
1022/** Prints the state of the matching object. Debug method.
1023 */
1024void ModelSimil::_PrintPartsMatching()
1025{
1026    // assure that matching exists
1027    assert(m_pMatching != NULL);
1028
1029    printf("Parts matching:\n");
1030    m_pMatching->PrintMatching();
1031}
1032
1033void ModelSimil::ComputeMatching()
1034{
1035    // uniwersalne liczniki
1036    int i, j;
1037
1038    assert(m_pMatching != NULL);
1039    assert(m_pMatching->IsEmpty() == true);
1040
1041    // rozpoczynamy etap dopasowywania Parts w organizmach
1042    // czy dopasowano już wszystkie Parts?
1043    int iCzyDopasowane = 0;
1044    // koniec grupy aktualnie dopasowywanej w każdym organizmie
1045    int aiKoniecGrupyDopasowania[2] = {0, 0};
1046    // koniec grupy już w całości dopasowanej
1047    // (Pomiedzy tymi dwoma indeksami znajduja sie Parts w tablicy
1048    // m_aDegrees, ktore moga byc dopasowywane (tam nadal moga
1049    // byc tez dopasowane - ale nie musi to byc w sposob
1050    // ciagly)
1051    int aiKoniecPierwszejGrupy[2] = {0, 0};
1052    // Tablica przechowująca odległości poszczególnych Parts z aktualnych
1053    // grup dopasowania. Rozmiar - prostokąt o bokach równych liczbie elementów w
1054    // dopasowywanych aktualnie grupach. Pierwszy wymiar - pierwszy organizm.
1055    // Drugi wymiar - drugi organizm (nie zależy to od tego, który jest mniejszy).
1056    // Wliczane w rozmiar tablicy są nawet już dopasowane elementy - tablice
1057    // paiCzyDopasowany pamiętają stan dopasowania tych elementów.
1058    typedef double *TPDouble;
1059    double **aadOdleglosciParts;
1060    // dwie tablice okreslajace Parts, ktore moga byc do siebie dopasowywane
1061    // rozmiary: [0] - aiRozmiarCalychGrup[1]
1062    //                   [1] - aiRozmiarCalychGrup[0]
1063    std::vector<bool> *apvbCzyMinimalnaOdleglosc[2];
1064    // rozmiar aktualnie dopasowywanej grupy w odpowiednim organizmie (tylko elementy
1065    // jeszcze niedopasowane).
1066    int aiRozmiarGrupy[2];
1067    // rozmiar aktualnie dopasowywanych grup w odpowiednim organizmie (włączone są
1068    // w to również elementy już dopasowane).
1069    int aiRozmiarCalychGrup[2] = {0, 0};
1070
1071    // utworzenie tablicy rozmiarow
1072    for (i = 0; i < 2; i++)
1073    {
1074        m_aiPartCount[i] = m_Mod[i]->getPartCount();
1075    }
1076
1077    // DOPASOWYWANIE PARTS
1078    while (!iCzyDopasowane)
1079    {
1080        // znajdz konce obu grup aktualnie dopasowywanych w obu organizmach
1081        for (i = 0; i < 2; i++)
1082        {
1083            // czyli poszukaj miejsca zmiany stopnia lub konca tablicy
1084            for (j = aiKoniecPierwszejGrupy[i] + 1; j < m_aiPartCount[i]; j++)
1085            {
1086                if (m_aDegrees[i][j][DEGREE] < m_aDegrees[i][j - 1][DEGREE])
1087                {
1088                    break;
1089                }
1090            }
1091            aiKoniecGrupyDopasowania[i] = j;
1092
1093            // sprawdz poprawnosc tego indeksu
1094            assert((aiKoniecGrupyDopasowania[i] > 0) &&
1095                   (aiKoniecGrupyDopasowania[i] <= m_aiPartCount[i]));
1096
1097            // oblicz rozmiary całych grup - łącznie z dopasowanymi już elementami
1098            aiRozmiarCalychGrup[i] = aiKoniecGrupyDopasowania[i] -
1099                    aiKoniecPierwszejGrupy[i];
1100
1101            // sprawdz teraz rozmiar tej grupy w sensie liczby niedopasowanzch
1102            // nie moze to byc puste!
1103            aiRozmiarGrupy[i] = 0;
1104            for (j = aiKoniecPierwszejGrupy[i]; j < aiKoniecGrupyDopasowania[i]; j++)
1105            {
1106                // od poczatku do konca grupy
1107                if (!m_pMatching->IsMatched(i, j))
1108                {
1109                    // jesli niedopasowany, to zwieksz licznik
1110                    aiRozmiarGrupy[i]++;
1111                }
1112            }
1113            // grupa nie moze byc pusta!
1114            assert(aiRozmiarGrupy[i] > 0);
1115        }
1116
1117        // DOPASOWYWANIE PARTS Z GRUP
1118
1119        // stworzenie tablicy odległości lokalnych
1120        // stwórz pierwszy wymiar - wg rozmiaru zerowego organizmu
1121        aadOdleglosciParts = new TPDouble[ aiRozmiarCalychGrup[0] ];
1122        assert(aadOdleglosciParts != NULL);
1123        // stwórz drugi wymiar - wg rozmiaru drugiego organizmu
1124        for (i = 0; i < aiRozmiarCalychGrup[0]; i++)
1125        {
1126            aadOdleglosciParts[i] = new double [ aiRozmiarCalychGrup[1] ];
1127            assert(aadOdleglosciParts[i] != NULL);
1128        }
1129
1130        // stworzenie tablic mozliwosci dopasowania (indykatorow minimalnej odleglosci)
1131        apvbCzyMinimalnaOdleglosc[0] = new std::vector<bool>(aiRozmiarCalychGrup[1], false);
1132        apvbCzyMinimalnaOdleglosc[1] = new std::vector<bool>(aiRozmiarCalychGrup[0], false);
1133        // sprawdz stworzenie tablic
1134        assert(apvbCzyMinimalnaOdleglosc[0] != NULL);
1135        assert(apvbCzyMinimalnaOdleglosc[1] != NULL);
1136
1137        // wypełnienie elementów macierzy (i,j) odległościami pomiędzy
1138        // odpowiednimi Parts: (i) w organizmie 0 i (j) w organizmie 1.
1139        // UWAGA! Uwzględniamy tylko te Parts, które nie są jeszcze dopasowane
1140        // (reszta to byłaby po prostu strata czasu).
1141        int iDeg, iNeu, iNIt; // ilościowe określenie różnic stopnia, liczby neuronów i połączeń Parts
1142        double dGeo; // ilościowe określenie różnic geometrycznych pomiędzy Parts
1143        // indeksy konkretnych Parts - indeksy sa ZERO-BASED, choć właściwy dostep
1144        // do informacji o Part wymaga dodania aiKoniecPierwszejGrupy[]
1145        // tylko aadOdleglosciParts[][] indeksuje sie bezposrednio zawartoscia iIndex[]
1146        int iIndex[2];
1147        int iPartIndex[ 2 ] = {-1, -1}; // at [iModel]: original index of a Part for the specified model (iModel)
1148
1149        // debug - wypisz zakres dopasowywanych indeksow
1150        DB(printf("Organizm 0: grupa: (%2i, %2i)\n", aiKoniecPierwszejGrupy[0],
1151                  aiKoniecGrupyDopasowania[0]);)
1152                DB(printf("Organizm 1: grupa: (%2i, %2i)\n", aiKoniecPierwszejGrupy[1],
1153                          aiKoniecGrupyDopasowania[1]);)
1154
1155        for (i = 0; i < aiRozmiarCalychGrup[0]; i++)
1156        {
1157
1158            // iterujemy i - Parts organizmu 0
1159            // (indeks podstawowy - aiKoniecPierwszejGrupy[0])
1160
1161            if (!(m_pMatching->IsMatched(0, aiKoniecPierwszejGrupy[0] + i)))
1162            {
1163                // interesuja nas tylko te niedopasowane jeszcze (i)
1164                for (j = 0; j < aiRozmiarCalychGrup[1]; j++)
1165                {
1166
1167                    // iterujemy j - Parts organizmu 1
1168                    // (indeks podstawowy - aiKoniecPierwszejGrupy[1])
1169
1170                    if (!(m_pMatching->IsMatched(1, aiKoniecPierwszejGrupy[1] + j)))
1171                    {
1172                        // interesuja nas tylko te niedopasowane jeszcze (j)
1173                        // teraz obliczymy lokalne różnice pomiędzy Parts
1174                        iDeg = abs(m_aDegrees[0][ aiKoniecPierwszejGrupy[0] + i ][1]
1175                                   - m_aDegrees[1][ aiKoniecPierwszejGrupy[1] + j ][1]);
1176
1177                        iNIt = abs(m_aDegrees[0][ aiKoniecPierwszejGrupy[0] + i ][2]
1178                                   - m_aDegrees[1][ aiKoniecPierwszejGrupy[1] + j ][2]);
1179
1180                        iNeu = abs(m_aDegrees[0][ aiKoniecPierwszejGrupy[0] + i ][3]
1181                                   - m_aDegrees[1][ aiKoniecPierwszejGrupy[1] + j ][3]);
1182
1183                        // obliczenie także lokalnych różnic geometrycznych pomiędzy Parts
1184                        // find original indices of Parts for both of the models
1185                        iPartIndex[ 0 ] = m_aDegrees[0][ aiKoniecPierwszejGrupy[0] + i ][ 0 ];
1186                        iPartIndex[ 1 ] = m_aDegrees[1][ aiKoniecPierwszejGrupy[1] + j ][ 0 ];
1187                        // now compute the geometrical distance of these Parts (use m_aPositions
1188                        // which should be computed by SVD)
1189                        Pt3D Part0Pos(m_aPositions[ 0 ][ iPartIndex[ 0 ] ]);
1190                        Pt3D Part1Pos(m_aPositions[ 1 ][ iPartIndex[ 1 ] ]);
1191                        dGeo = m_adFactors[3] == 0 ? 0 : Part0Pos.distanceTo(Part1Pos); //no need to compute distane when m_dDG weight is 0
1192
1193                        // tutaj prawdopodobnie należy jeszcze dodać sprawdzanie
1194                        // identyczności pozostałych własności (oprócz geometrii)
1195                        // - żeby móc stwierdzić w ogóle identyczność Parts
1196
1197                        // i ostateczna odleglosc indukowana przez te roznice
1198                        // (tutaj nie ma różnicy w liczbie wszystkich wierzchołków)
1199                        aadOdleglosciParts[i][j] = m_adFactors[1] * double(iDeg) +
1200                                m_adFactors[2] * double(iNeu) +
1201                                m_adFactors[3] * dGeo;
1202                        DB(printf("Parts Distance (%2i,%2i) = %.3lf\n", aiKoniecPierwszejGrupy[0] + i,
1203                                  aiKoniecPierwszejGrupy[1] + j, aadOdleglosciParts[i][j]);)
1204                                DB(printf("Parts geometrical distance = %.20lf\n", dGeo);)
1205                                DB(printf("Pos0: (%.3lf %.3lf %.3lf)\n", Part0Pos.x, Part0Pos.y, Part0Pos.z);)
1206                                DB(printf("Pos1: (%.3lf %.3lf %.3lf)\n", Part1Pos.x, Part1Pos.y, Part1Pos.z);)
1207                    }
1208                }
1209            }
1210        }
1211
1212        // tutaj - sprawdzic tylko, czy tablica odleglosci lokalnych jest poprawnie obliczona
1213
1214        // WYKORZYSTANIE TABLICY ODLEGLOSCI DO BUDOWY DOPASOWANIA
1215
1216        // trzeba raczej iterować aż do zebrania wszystkich możliwych dopasowań w grupie
1217        // dlatego wprowadzamy dodatkowa zmienna - czy skonczyla sie juz grupa
1218        bool bCzyKoniecGrupy = false;
1219        while (!bCzyKoniecGrupy)
1220        {
1221            for (i = 0; i < 2; i++)
1222            {
1223                // iterujemy (i) po organizmach
1224                // szukamy najpierw jakiegoś niedopasowanego jeszcze Part w organizmach
1225
1226                // zakładamy, że nie ma takiego Part
1227                iIndex[i] = -1;
1228
1229                for (j = 0; j < aiRozmiarCalychGrup[ i ]; j++)
1230                {
1231                    // iterujemy (j) - Parts organizmu (i)
1232                    // (indeks podstawowy - aiKoniecPierwszejGrupy[0])
1233                    if (!(m_pMatching->IsMatched(i, aiKoniecPierwszejGrupy[i] + j)))
1234                    {
1235                        // gdy mamy w tej grupie jakis niedopasowany element, to ustawiamy
1236                        // iIndex[i] (chcemy w zasadzie pierwszy taki)
1237                        iIndex[i] = j;
1238                        break;
1239                    }
1240                }
1241
1242                // sprawdzamy, czy w ogole znaleziono taki Part
1243                if (iIndex[i] < 0)
1244                {
1245                    // gdy nie znaleziono takiego Part - mamy koniec dopasowywania w
1246                    // tych grupach
1247                    bCzyKoniecGrupy = true;
1248                }
1249                // sprawdz poprawnosc indeksu niedopasowanego Part - musi byc w aktualnej grupie
1250                assert((iIndex[i] >= -1) && (iIndex[i] < aiRozmiarCalychGrup[i]));
1251            }
1252
1253
1254            // teraz mamy sytuacje:
1255            // - mamy w iIndex[0] i iIndex[1] indeksy pierwszych niedopasowanych Part
1256            //          w organizmach, albo
1257            // - nie ma w ogóle już czego dopasowywać (należy przejść do innej grupy)
1258            if (!bCzyKoniecGrupy)
1259            {
1260                // gdy nie ma jeszcze końca żadnej z grup - możemy dopasowywać
1261                // najpierw wyszukujemy w tablicy minimum odległości od tych
1262                // wyznaczonych Parts
1263
1264                // najpierw wyczyscimy wektory potencjalnych dopasowan
1265                // dla organizmu 1 (o rozmiarze grupy z 0)
1266                for (i = 0; i < aiRozmiarCalychGrup[0]; i++)
1267                {
1268                    apvbCzyMinimalnaOdleglosc[1]->operator[](i) = false;
1269                }
1270                // dla organizmu 0 (o rozmiarze grup z 1)
1271                for (i = 0; i < aiRozmiarCalychGrup[1]; i++)
1272                {
1273                    apvbCzyMinimalnaOdleglosc[0]->operator[](i) = false;
1274                }
1275
1276                // szukanie minimum dla Part o indeksie iIndex[0] w organizmie 0
1277                // wsrod niedopasowanych Parts z organizmu 1
1278                // zakładamy, że nie znaleŸliśmy jeszcze minimum
1279                double dMinimum = HUGE_VAL;
1280                for (i = 0; i < aiRozmiarCalychGrup[1]; i++)
1281                {
1282                    if (!(m_pMatching->IsMatched(1, aiKoniecPierwszejGrupy[1] + i)))
1283                    {
1284
1285                        // szukamy minimum obliczonej lokalnej odleglosci tylko wsrod
1286                        // niedopasowanych jeszcze Parts
1287                        if (aadOdleglosciParts[ iIndex[0] ][ i ] < dMinimum)
1288                        {
1289                            dMinimum = aadOdleglosciParts[ iIndex[0] ][ i ];
1290                        }
1291
1292                        // przy okazji - sprawdz, czy HUGE_VAL jest rzeczywiscie max dla double
1293                        assert(aadOdleglosciParts[ iIndex[0] ][ i ] < HUGE_VAL);
1294                    }
1295                }
1296                // sprawdz, czy minimum znaleziono - musi takie byc, bo jest cos niedopasowanego
1297                assert((dMinimum >= 0.0) && (dMinimum < HUGE_VAL));
1298
1299                // teraz zaznaczamy w tablicy te wszystkie Parts, ktore maja
1300                // rzeczywiscie te minimalna odleglosc do Part iIndex[0] w organizmie 0
1301                for (i = 0; i < aiRozmiarCalychGrup[1]; i++)
1302                {
1303                    if (!(m_pMatching->IsMatched(1, aiKoniecPierwszejGrupy[1] + i)))
1304                    {
1305                        if (aadOdleglosciParts[ iIndex[0] ][ i ] == dMinimum)
1306                        {
1307                            // jesli w danym miejscu tablicy odleglosci jest faktyczne
1308                            // minimum odleglosci, to mamy potencjalna pare dla iIndex[0]
1309                            apvbCzyMinimalnaOdleglosc[0]->operator[](i) = true;
1310                        }
1311
1312                        // sprawdz poprawnosc znalezionego wczesniej minimum
1313                        assert(aadOdleglosciParts[ iIndex[0] ][ i ] >= dMinimum);
1314                    }
1315                }
1316
1317                // podobnie szukamy minimum dla Part o indeksie iIndex[1] w organizmie 1
1318                // wsrod niedopasowanych Parts z organizmu 0
1319                dMinimum = HUGE_VAL;
1320                for (i = 0; i < aiRozmiarCalychGrup[0]; i++)
1321                {
1322                    if (!(m_pMatching->IsMatched(0, aiKoniecPierwszejGrupy[0] + i)))
1323                    {
1324                        // szukamy minimum obliczonej lokalnej odleglosci tylko wsrod
1325                        // niedopasowanych jeszcze Parts
1326                        if (aadOdleglosciParts[ i ][ iIndex[1] ] < dMinimum)
1327                        {
1328                            dMinimum = aadOdleglosciParts[ i ][ iIndex[1] ];
1329                        }
1330                        // przy okazji - sprawdz, czy HUGE_VAL jest rzeczywiscie max dla double
1331                        assert(aadOdleglosciParts[ i ][ iIndex[1] ] < HUGE_VAL);
1332                    }
1333                }
1334                // sprawdz, czy minimum znaleziono - musi takie byc, bo jest cos niedopasowanego
1335                assert((dMinimum >= 0.0) && (dMinimum < HUGE_VAL));
1336
1337                // teraz zaznaczamy w tablicy te wszystkie Parts, ktore maja
1338                // rzeczywiscie te minimalne odleglosci do Part iIndex[1] w organizmie 1
1339                for (i = 0; i < aiRozmiarCalychGrup[0]; i++)
1340                {
1341                    if (!(m_pMatching->IsMatched(0, aiKoniecPierwszejGrupy[0] + i)))
1342                    {
1343                        if (aadOdleglosciParts[ i ][ iIndex[1] ] == dMinimum)
1344                        {
1345                            // jesli w danym miejscu tablicy odleglosci jest faktyczne
1346                            // minimum odleglosci, to mamy potencjalna pare dla iIndex[1]
1347                            apvbCzyMinimalnaOdleglosc[1]->operator[](i) = true;
1348                        }
1349
1350                        // sprawdz poprawnosc znalezionego wczesniej minimum
1351                        assert(aadOdleglosciParts[ i ][ iIndex[1] ] >= dMinimum);
1352                    }
1353                }
1354
1355                // teraz mamy juz poszukane potencjalne grupy dopasowania - musimy
1356                // zdecydowac, co do czego dopasujemy!
1357                // szukamy Part iIndex[0] posrod mozliwych do dopasowania dla Part iIndex[1]
1358                // szukamy takze Part iIndex[1] posrod mozliwych do dopasowania dla Part iIndex[0]
1359                bool PartZ1NaLiscie0 = apvbCzyMinimalnaOdleglosc[0]->operator[](iIndex[1]);
1360                bool PartZ0NaLiscie1 = apvbCzyMinimalnaOdleglosc[1]->operator[](iIndex[0]);
1361
1362                if (PartZ1NaLiscie0 && PartZ0NaLiscie1)
1363                {
1364                    // PRZYPADEK 1. Oba Parts maja sie wzajemnie na listach mozliwych
1365                    // dopasowan.
1366                    // AKCJA. Dopasowanie wzajemne do siebie.
1367
1368                    m_pMatching->Match(0, aiKoniecPierwszejGrupy[0] + iIndex[0],
1369                                       1, aiKoniecPierwszejGrupy[1] + iIndex[1]);
1370
1371                    // zmniejsz liczby niedopasowanych elementow w grupach
1372                    aiRozmiarGrupy[0]--;
1373                    aiRozmiarGrupy[1]--;
1374                    // debug - co zostalo dopasowane
1375                    DB(printf("Przypadek 1.: dopasowane Parts: (%2i, %2i)\n", aiKoniecPierwszejGrupy[0]
1376                              + iIndex[0], aiKoniecPierwszejGrupy[1] + iIndex[1]);)
1377
1378                }// PRZYPADEK 1.
1379                else
1380                    if (PartZ1NaLiscie0 || PartZ0NaLiscie1)
1381                {
1382                    // PRZYPADEK 2. Tylko jeden z Parts ma drugiego na swojej liscie
1383                    // mozliwych dopasowan
1384                    // AKCJA. Dopasowanie jednego jest proste (tego, ktory nie ma
1385                    // na swojej liscie drugiego). Dla tego drugiego nalezy powtorzyc
1386                    // duza czesc obliczen (znalezc mu nowa mozliwa pare)
1387
1388                    // indeks organizmu, ktorego Part nie ma dopasowywanego Part
1389                    // z drugiego organizmu na swojej liscie
1390                    int iBezDrugiego;
1391
1392                    // okreslenie indeksu organizmu z dopasowywanym Part
1393                    if (!PartZ1NaLiscie0)
1394                    {
1395                        iBezDrugiego = 0;
1396                    }
1397                    else
1398                    {
1399                        iBezDrugiego = 1;
1400                    }
1401                    // sprawdz indeks organizmu
1402                    assert((iBezDrugiego == 0) || (iBezDrugiego == 1));
1403
1404                    int iDopasowywany = -1;
1405                    // poszukujemy pierwszego z listy dopasowania
1406                    for (i = 0; i < aiRozmiarCalychGrup[ 1 - iBezDrugiego ]; i++)
1407                    {
1408                        if (apvbCzyMinimalnaOdleglosc[iBezDrugiego]->operator[](i))
1409                        {
1410                            iDopasowywany = i;
1411                            break;
1412                        }
1413                    }
1414                    // sprawdz poprawnosc indeksu dopasowywanego (musimy cos znalezc!)
1415                    // nieujemny i w odpowiedniej grupie!
1416                    assert((iDopasowywany >= 0) &&
1417                           (iDopasowywany < aiRozmiarCalychGrup[ 1 - iBezDrugiego ]));
1418
1419                    // znalezlismy 1. Part z listy dopasowania - dopasowujemy!
1420                    m_pMatching->Match(
1421                                       iBezDrugiego,
1422                                       aiKoniecPierwszejGrupy[ iBezDrugiego ] + iIndex[ iBezDrugiego ],
1423                                       1 - iBezDrugiego,
1424                                       aiKoniecPierwszejGrupy[ 1 - iBezDrugiego ] + iDopasowywany);
1425                    DB(printf("Przypadek 2.1.: dopasowane Parts dopasowanie bez drugiego: (%2i, %2i)\n", aiKoniecPierwszejGrupy[ iBezDrugiego ] + iIndex[ iBezDrugiego ],
1426                              aiKoniecPierwszejGrupy[ 1 - iBezDrugiego ] + iDopasowywany);)
1427
1428                            // zmniejsz liczby niedopasowanych elementow w grupach
1429                            aiRozmiarGrupy[0]--;
1430                    aiRozmiarGrupy[1]--;
1431
1432                    // sprawdz, czy jest szansa dopasowania tego Part z drugiej strony
1433                    // (ktora miala mozliwosc dopasowania tego Part z poprzedniego organizmu)
1434                    if ((aiRozmiarGrupy[0] > 0) && (aiRozmiarGrupy[1] > 0))
1435                    {
1436                        // jesli grupy sie jeszcze nie wyczrpaly
1437                        // to jest mozliwosc dopasowania w organizmie
1438
1439                        int iZDrugim = 1 - iBezDrugiego;
1440                        // sprawdz indeks organizmu
1441                        assert((iZDrugim == 0) || (iZDrugim == 1));
1442
1443                        // bedziemy szukac minimum wsrod niedopasowanych - musimy wykasowac
1444                        // poprzednie obliczenia minimum
1445                        // dla organizmu 1 (o rozmiarze grupy z 0)
1446                        for (i = 0; i < aiRozmiarCalychGrup[0]; i++)
1447                        {
1448                            apvbCzyMinimalnaOdleglosc[1]->operator[](i) = false;
1449                        }
1450                        // dla organizmu 0 (o rozmiarze grup z 1)
1451                        for (i = 0; i < aiRozmiarCalychGrup[1]; i++)
1452                        {
1453                            apvbCzyMinimalnaOdleglosc[0]->operator[](i) = false;
1454                        }
1455
1456                        // szukamy na nowo minimum dla Part o indeksie iIndex[ iZDrugim ] w organizmie iZDrugim
1457                        // wsrod niedopasowanych Parts z organizmu 1 - iZDrugim
1458                        dMinimum = HUGE_VAL;
1459                        for (i = 0; i < aiRozmiarCalychGrup[ 1 - iZDrugim ]; i++)
1460                        {
1461                            if (!(m_pMatching->IsMatched(
1462                                                         1 - iZDrugim,
1463                                                         aiKoniecPierwszejGrupy[ 1 - iZDrugim ] + i)))
1464                            {
1465                                // szukamy minimum obliczonej lokalnej odleglosci tylko wsrod
1466                                // niedopasowanych jeszcze Parts
1467                                if (iZDrugim == 0)
1468                                {
1469                                    // teraz niestety musimy rozpoznac odpowiedni organizm
1470                                    // zeby moc indeksowac niesymetryczna tablice
1471                                    if (aadOdleglosciParts[ iIndex[0] ][ i ] < dMinimum)
1472                                    {
1473                                        dMinimum = aadOdleglosciParts[ iIndex[0] ][ i ];
1474                                    }
1475                                    // przy okazji - sprawdz, czy HUGE_VAL jest rzeczywiscie max dla double
1476                                    assert(aadOdleglosciParts[ iIndex[0] ][ i ] < HUGE_VAL);
1477
1478                                }
1479                                else
1480                                {
1481                                    if (aadOdleglosciParts[ i ][ iIndex[1] ] < dMinimum)
1482                                    {
1483                                        dMinimum = aadOdleglosciParts[ i ][ iIndex[1] ];
1484                                    }
1485                                    // przy okazji - sprawdz, czy HUGE_VAL jest rzeczywiscie max dla double
1486                                    assert(aadOdleglosciParts[ i ][ iIndex[1] ] < HUGE_VAL);
1487                                }
1488                            }
1489                        }
1490                        // sprawdz, czy minimum znaleziono - musi takie byc, bo jest cos niedopasowanego
1491                        assert((dMinimum >= 0.0) && (dMinimum < HUGE_VAL));
1492
1493                        // teraz zaznaczamy w tablicy te wszystkie Parts, ktore maja
1494                        // rzeczywiscie te minimalne odleglosci do Part w organizmie iZDrugim
1495                        for (i = 0; i < aiRozmiarCalychGrup[ 1 - iZDrugim ]; i++)
1496                        {
1497                            if (!(m_pMatching->IsMatched(
1498                                                         1 - iZDrugim,
1499                                                         aiKoniecPierwszejGrupy[ 1 - iZDrugim ] + i)))
1500                            {
1501                                if (iZDrugim == 0)
1502                                {
1503                                    // teraz niestety musimy rozpoznac odpowiedni organizm
1504                                    // zeby moc indeksowac niesymetryczna tablice
1505                                    if (aadOdleglosciParts[ iIndex[0] ][ i ] == dMinimum)
1506                                    {
1507                                        // jesli w danym miejscu tablicy odleglosci jest faktyczne
1508                                        // minimum odleglosci, to mamy potencjalna pare dla iIndex[1]
1509                                        apvbCzyMinimalnaOdleglosc[0]->operator[](i) = true;
1510                                    }
1511                                }
1512                                else
1513                                {
1514                                    if (aadOdleglosciParts[ i ][ iIndex[1] ] == dMinimum)
1515                                    {
1516                                        apvbCzyMinimalnaOdleglosc[1]->operator[](i) = true;
1517                                    }
1518                                }
1519                            }
1520                        }
1521
1522                        // a teraz - po znalezieniu potencjalnych elementow do dopasowania
1523                        // dopasowujemy pierwszy z potencjalnych
1524                        iDopasowywany = -1;
1525                        for (i = 0; i < aiRozmiarCalychGrup[ 1 - iZDrugim ]; i++)
1526                        {
1527                            if (apvbCzyMinimalnaOdleglosc[iZDrugim]->operator[](i))
1528                            {
1529                                iDopasowywany = i;
1530                                break;
1531                            }
1532                        }
1533                        // musielismy znalezc jakiegos dopasowywanego
1534                        assert((iDopasowywany >= 0) &&
1535                               (iDopasowywany < aiRozmiarCalychGrup[ 1 - iZDrugim ]));
1536
1537                        // no to juz mozemy dopasowac
1538                        m_pMatching->Match(
1539                                           iZDrugim,
1540                                           aiKoniecPierwszejGrupy[ iZDrugim ] + iIndex[ iZDrugim ],
1541                                           1 - iZDrugim,
1542                                           aiKoniecPierwszejGrupy[ 1 - iZDrugim ] + iDopasowywany);
1543                        DB(printf("Przypadek 2.1.: dopasowane Parts dopasowaniebz drugim: (%2i, %2i)\n", aiKoniecPierwszejGrupy[ iZDrugim ] + iIndex[ iZDrugim ], aiKoniecPierwszejGrupy[ 1 - iZDrugim ] + iDopasowywany);)
1544
1545                        //aiKoniecPierwszejGrupy[ 1-iBezDrugiego ] + iDopasowywany ;)
1546                        //aiKoniecPierwszejGrupy[ 1-iBezDrugiego ] + iDopasowywany ;)
1547                        // zmniejsz liczby niedopasowanych elementow w grupach
1548                        aiRozmiarGrupy[0]--;
1549                        aiRozmiarGrupy[1]--;
1550
1551                    }
1552                    else
1553                    {
1554                        // jedna z grup sie juz wyczerpala
1555                        // wiec nie ma mozliwosci dopasowania tego drugiego Partu
1556                        /// i trzeba poczekac na zmiane grupy
1557                    }
1558
1559                    DB(printf("Przypadek 2.\n");)
1560
1561                }// PRZYPADEK 2.
1562                else
1563                {
1564                    // PRZYPADEK 3. Zaden z Parts nie ma na liscie drugiego
1565                    // AKCJA. Niezalezne dopasowanie obu Parts do pierwszych ze swojej listy
1566
1567                    // najpierw dopasujemy do iIndex[0] w organizmie 0
1568                    int iDopasowywany = -1;
1569                    // poszukujemy pierwszego z listy dopasowania - w organizmie 1
1570                    for (i = 0; i < aiRozmiarCalychGrup[1]; i++)
1571                    {
1572                        if (apvbCzyMinimalnaOdleglosc[0]->operator[](i))
1573                        {
1574                            iDopasowywany = i;
1575                            break;
1576                        }
1577                    }
1578                    // musielismy znalezc jakiegos dopasowywanego
1579                    assert((iDopasowywany >= 0) &&
1580                           (iDopasowywany < aiRozmiarCalychGrup[1]));
1581
1582                    // teraz wlasnie dopasowujemy
1583                    m_pMatching->Match(
1584                                       0,
1585                                       aiKoniecPierwszejGrupy[0] + iIndex[0],
1586                                       1,
1587                                       aiKoniecPierwszejGrupy[1] + iDopasowywany);
1588
1589                    // zmniejszamy liczbe niedopasowanych Parts
1590                    aiRozmiarGrupy[0]--;
1591                    aiRozmiarGrupy[1]--;
1592
1593                    // debug - dopasowanie
1594                    DB(printf("Przypadek 3.: dopasowane Parts: (%2i, %2i)\n", aiKoniecPierwszejGrupy[0]
1595                              + iIndex[0], aiKoniecPierwszejGrupy[1] + iDopasowywany);)
1596
1597                            // teraz dopasowujemy do iIndex[1] w organizmie 1
1598                            iDopasowywany = -1;
1599                    // poszukujemy pierwszego z listy dopasowania - w organizmie 0
1600                    for (i = 0; i < aiRozmiarCalychGrup[0]; i++)
1601                    {
1602                        if (apvbCzyMinimalnaOdleglosc[1]->operator[](i))
1603                        {
1604                            iDopasowywany = i;
1605                            break;
1606                        }
1607                    }
1608                    // musielismy znalezc jakiegos dopasowywanego
1609                    assert((iDopasowywany >= 0) &&
1610                           (iDopasowywany < aiRozmiarCalychGrup[0]));
1611
1612                    // no i teraz realizujemy dopasowanie
1613                    m_pMatching->Match(
1614                                       0,
1615                                       aiKoniecPierwszejGrupy[0] + iDopasowywany,
1616                                       1,
1617                                       aiKoniecPierwszejGrupy[1] + iIndex[1]);
1618
1619                    // zmniejszamy liczbe niedopasowanych Parts
1620                    aiRozmiarGrupy[0]--;
1621                    aiRozmiarGrupy[1]--;
1622
1623                    // debug - dopasowanie
1624                    DB(printf("Przypadek 3.: dopasowane Parts: (%2i, %2i)\n", aiKoniecPierwszejGrupy[0]
1625                              + iDopasowywany, aiKoniecPierwszejGrupy[1] + iIndex[1]);)
1626
1627
1628                } // PRZYPADEK 3.
1629
1630            }// if (! bCzyKoniecGrupy)
1631            else
1632            {
1633                // gdy mamy już koniec grup - musimy zlikwidować tablicę aadOdleglosciParts
1634                // bo za chwilke skonczy sie nam petla
1635                for (i = 0; i < aiRozmiarCalychGrup[0]; i++)
1636                {
1637                    SAFEDELETEARRAY(aadOdleglosciParts[i]);
1638                }
1639                SAFEDELETEARRAY(aadOdleglosciParts);
1640
1641                // musimy tez usunac tablice (wektory) mozliwosci dopasowania
1642                SAFEDELETE(apvbCzyMinimalnaOdleglosc[0]);
1643                SAFEDELETE(apvbCzyMinimalnaOdleglosc[1]);
1644            }
1645        } // while (! bCzyKoniecGrupy)
1646
1647        // PO DOPASOWANIU WSZYSTKIEGO Z GRUP (CO NAJMNIEJ JEDNEJ GRUPY W CAŁOŚCI)
1648
1649        // gdy rozmiar ktorejkolwiek z grup dopasowania spadl do zera
1650        // to musimy przesunac KoniecPierwszejGrupy (wszystkie dopasowane)
1651        for (i = 0; i < 2; i++)
1652        {
1653            // grupy nie moga miec mniejszego niz 0 rozmiaru
1654            assert(aiRozmiarGrupy[i] >= 0);
1655            if (aiRozmiarGrupy[i] == 0)
1656                aiKoniecPierwszejGrupy[i] = aiKoniecGrupyDopasowania[i];
1657        }
1658
1659        // sprawdzenie warunku konca dopasowywania - gdy nie
1660        // ma juz w jakims organizmie co dopasowywac
1661        if (aiKoniecPierwszejGrupy[0] >= m_aiPartCount[0] ||
1662                aiKoniecPierwszejGrupy[1] >= m_aiPartCount[1])
1663        {
1664            iCzyDopasowane = 1;
1665        }
1666    } // koniec WHILE - petli dopasowania
1667}
1668
1669/** Matches Parts in both organisms so that computation of similarity is possible.
1670    New algorithm (assures symmetry of the similarity measure) with geometry
1671    taken into consideration.
1672    Assumptions:
1673    - Models (m_Mod) are created and available.
1674        - Matching (m_pMatching) is created, but empty
1675        Exit conditions:
1676        - Matching (m_pMatching) is full
1677        @return 1 if success, 0 otherwise
1678 */
1679int ModelSimil::MatchPartsGeometry()
1680{
1681    // zaloz, ze sa modele i sa poprawne
1682    assert((m_Mod[0] != NULL) && (m_Mod[1] != NULL));
1683    assert(m_Mod[0]->isValid() && m_Mod[1]->isValid());
1684
1685    if (!CreatePartInfoTables())
1686        return 0;
1687    if (!CountPartDegrees())
1688        return 0;
1689    if (!GetPartPositions())
1690    {
1691        return 0;
1692    }
1693    if (!CountPartNeurons())
1694        return 0;
1695
1696
1697    if (m_adFactors[3] > 0)
1698    {
1699        if (!ComputePartsPositionsBySVD())
1700        {
1701            return 0;
1702        }
1703    }
1704
1705    DB(printf("Przed sortowaniem:\n");)
1706    DB(_PrintDegrees(0);)
1707    DB(_PrintDegrees(1);)
1708
1709    if (!SortPartInfoTables())
1710        return 0;
1711
1712    DB(printf("Po sortowaniu:\n");)
1713    DB(_PrintDegrees(0);)
1714    DB(_PrintDegrees(1);)
1715
1716    if (m_adFactors[3] > 0)
1717    {
1718        // tutaj zacznij pętlę po przekształceniach  geometrycznych
1719        const int NO_OF_TRANSFORM = 8; // liczba transformacji geometrycznych (na razie tylko ID i O_YZ)
1720        // tablice transformacji współrzędnych; nie są to dokładnie tablice tranformacji, ale raczej tablice PRZEJŚĆ
1721        // pomiędzy transformacjami;
1722        // wartości orginalne transformacji dOrig uzyskuje się przez:
1723        // for ( iTrans = 0; iTrans <= TRANS_INDEX; iTrans++ ) dOrig *= dMul[ iTrans ];
1724        const int dMulX[ NO_OF_TRANSFORM ] = {1, -1, -1, 1, -1, 1, -1, -1};
1725        const int dMulY[ NO_OF_TRANSFORM ] = {1, 1, -1, -1, -1, -1, -1, 1};
1726        const int dMulZ[ NO_OF_TRANSFORM ] = {1, 1, 1, -1, -1, -1, 1, 1};
1727
1728#undef max
1729        double dMinSimValue = std::numeric_limits<double>::max(); // minimum value of similarity
1730        int iMinSimTransform = -1; // index of the transformation with the minimum similarity
1731        SimilMatching *pMinSimMatching = NULL; // matching with the minimum value of similarity
1732
1733        // remember the original positions of model 0 as computed by SVD in order to restore them later, after
1734        // all transformations have been computed
1735        Pt3D *StoredPositions = NULL; // array of positions of Parts, for one (0th) model
1736        // create the stored positions
1737        StoredPositions = new Pt3D[ m_Mod[ 0 ]->getPartCount() ];
1738        assert(StoredPositions != NULL);
1739        // copy the original positions of model 0 (store them)
1740        int iPart; // a counter of Parts
1741        for (iPart = 0; iPart < m_Mod[ 0 ]->getPartCount(); iPart++)
1742        {
1743            StoredPositions[ iPart ].x = m_aPositions[ 0 ][ iPart ].x;
1744            StoredPositions[ iPart ].y = m_aPositions[ 0 ][ iPart ].y;
1745            StoredPositions[ iPart ].z = m_aPositions[ 0 ][ iPart ].z;
1746        }
1747        // now the original positions of model 0 are stored
1748
1749
1750        int iTransform; // a counter of geometric transformations
1751        for (iTransform = 0; iTransform < NO_OF_TRANSFORM; iTransform++)
1752        {
1753            // for each geometric transformation to be done
1754            // entry conditions:
1755            // - models (m_Mod) exist and are available
1756            // - matching (m_pMatching) exists and is empty
1757            // - all properties are created and available (m_aDegrees and m_aPositions)
1758
1759            // recompute geometric properties according to the transformation iTransform
1760            // but only for model 0
1761            for (iPart = 0; iPart < m_Mod[ 0 ]->getPartCount(); iPart++)
1762            {
1763                // for each iPart, a part of the model iMod
1764                m_aPositions[ 0 ][ iPart ].x *= dMulX[ iTransform ];
1765                m_aPositions[ 0 ][ iPart ].y *= dMulY[ iTransform ];
1766                m_aPositions[ 0 ][ iPart ].z *= dMulZ[ iTransform ];
1767            }
1768            // now the positions are recomputed
1769            ComputeMatching();
1770
1771            // teraz m_pMatching istnieje i jest pełne
1772            assert(m_pMatching != NULL);
1773            assert(m_pMatching->IsFull() == true);
1774
1775            // wykorzystaj to dopasowanie i geometrię do obliczenia tymczasowej wartości miary
1776            int iTempRes = CountPartsDistance();
1777            // załóż sukces
1778            assert(iTempRes == 1);
1779            double dCurrentSim = m_adFactors[0] * double(m_iDV) +
1780                    m_adFactors[1] * double(m_iDD) +
1781                    m_adFactors[2] * double(m_iDN) +
1782                    m_adFactors[3] * double(m_dDG);
1783            // załóż poprawną wartość podobieństwa
1784            assert(dCurrentSim >= 0.0);
1785
1786            // porównaj wartość obliczoną z dotychczasowym minimum
1787            if (dCurrentSim < dMinSimValue)
1788            {
1789                // jeśli uzyskano mniejszą wartość dopasowania,
1790                // to zapamiętaj to przekształcenie geometryczne i dopasowanie
1791                dMinSimValue = dCurrentSim;
1792                iMinSimTransform = iTransform;
1793                SAFEDELETE(pMinSimMatching);
1794                pMinSimMatching = new SimilMatching(*m_pMatching);
1795                assert(pMinSimMatching != NULL);
1796            }
1797
1798            // teraz już można usunąć stare dopasowanie (dla potrzeb następnego przebiegu pętli)
1799            m_pMatching->Empty();
1800        } // for ( iTransform )
1801
1802        // po pętli przywróć najlepsze dopasowanie
1803        delete m_pMatching;
1804        m_pMatching = pMinSimMatching;
1805
1806        DB(printf("Matching has been chosen!\n");)
1807                // print the name of the chosen transformation:
1808                // printf("Chosen transformation: %s\n", szTransformNames[ iMinSimTransform ] );
1809
1810                // i przywróć jednocześnie pozycje Parts modelu 0 dla tego dopasowania
1811                // - najpierw przywroc Parts pozycje orginalne, po SVD
1812        for (iPart = 0; iPart < m_Mod[ 0 ]->getPartCount(); iPart++)
1813        {
1814            m_aPositions[ 0 ][ iPart ].x = StoredPositions[ iPart ].x;
1815            m_aPositions[ 0 ][ iPart ].y = StoredPositions[ iPart ].y;
1816            m_aPositions[ 0 ][ iPart ].z = StoredPositions[ iPart ].z;
1817        }
1818        // - usun teraz zapamietane pozycje Parts
1819        delete [] StoredPositions;
1820        // - a teraz oblicz na nowo wspolrzedne wlasciwego przeksztalcenia dla model 0
1821        for (iTransform = 0; iTransform <= iMinSimTransform; iTransform++)
1822        {
1823            // for each transformation before and INCLUDING iMinTransform
1824            // do the transformation (only model 0)
1825            for (iPart = 0; iPart < m_Mod[ 0 ]->getPartCount(); iPart++)
1826            {
1827                m_aPositions[ 0 ][ iPart ].x *= dMulX[ iTransform ];
1828                m_aPositions[ 0 ][ iPart ].y *= dMulY[ iTransform ];
1829                m_aPositions[ 0 ][ iPart ].z *= dMulZ[ iTransform ];
1830            }
1831        }
1832
1833    }
1834    else
1835    {
1836        ComputeMatching();
1837    }
1838    // teraz dopasowanie musi byc pelne - co najmniej w jednym organizmie musza byc
1839    // wszystkie elementy dopasowane
1840    assert(m_pMatching->IsFull() == true);
1841
1842    //    _PrintDegrees(0);
1843    //    _PrintDegrees(1);
1844
1845    DB(_PrintPartsMatching();)
1846
1847
1848    return 1;
1849}
1850
1851void ModelSimil::_PrintSeamnessTable(std::vector<int> *pTable, int iCount)
1852{
1853    int i;
1854    printf("      ");
1855    for (i = 0; i < iCount; i++)
1856        printf("%3i ", i);
1857    printf("\n      ");
1858    for (i = 0; i < iCount; i++)
1859    {
1860
1861        printf("%3i ", pTable->operator[](i));
1862    }
1863    printf("\n");
1864}
1865
1866/** Computes elements of similarity (m_iDD, m_iDN, m_dDG) based on underlying matching.
1867    Assumptions:
1868    - Matching (m_pMatching) exists and is full.
1869        - Internal arrays m_aDegrees and m_aPositions exist and are properly filled in
1870        Exit conditions:
1871        - Elements of similarity are computed (m)iDD, m_iDN, m_dDG).
1872        @return 1 if success, otherwise 0.
1873 */
1874int ModelSimil::CountPartsDistance()
1875{
1876    int i, temp;
1877
1878    // assume existence of m_pMatching
1879    assert(m_pMatching != NULL);
1880    // musi byc pelne!
1881    assert(m_pMatching->IsFull() == true);
1882
1883    // roznica w stopniach
1884    m_iDD = 0;
1885    // roznica w liczbie neuronów
1886    m_iDN = 0;
1887    // roznica w odleglosci dopasowanych Parts
1888    m_dDG = 0.0;
1889
1890    int iOrgPart, iOrgMatchedPart; // orginalny indeks Part i jego dopasowanego Part
1891    int iMatchedPart; // indeks (wg sortowania) dopasowanego Part
1892
1893    // wykorzystanie dopasowania do zliczenia m_iDD - roznicy w stopniach
1894    // i m_iDN - roznicy w liczbie neuronow
1895    // petla w wiekszej tablicy
1896    for (i = 0; i < m_aiPartCount[1 - m_iSmaller]; i++)
1897    {
1898        // dla kazdego elementu [i] z wiekszego organizmu
1899        // pobierz jego orginalny indeks w organizmie z tablicy TDN
1900        iOrgPart = m_aDegrees[ 1 - m_iSmaller ][ i ][ 0 ];
1901        if (!(m_pMatching->IsMatched(1 - m_iSmaller, i)))
1902        {
1903            // gdy nie zostal dopasowany
1904            // dodaj jego stopien do DD
1905            m_iDD += m_aDegrees[1 - m_iSmaller][i][1];
1906            // dodaj liczbe neuronow do DN
1907            m_iDN += m_aDegrees[1 - m_iSmaller][i][3];
1908            // i oblicz odleglosc tego Part od srodka organizmu (0,0,0)
1909            // (uzyj orginalnego indeksu)
1910            //no need to compute distane when m_dDG weight is 0
1911            m_dDG += m_adFactors[3] == 0 ? 0 : m_aPositions[ 1 - m_iSmaller ][ iOrgPart ].length();
1912        }
1913        else
1914        {
1915            // gdy byl dopasowany
1916            // pobierz indeks (po sortowaniu) tego dopasowanego Part
1917            iMatchedPart = m_pMatching->GetMatchedIndex(1 - m_iSmaller, i);
1918            // pobierz indeks orginalny tego dopasowanego Part
1919            iOrgMatchedPart = m_aDegrees[ m_iSmaller ][ iMatchedPart ][0];
1920            // dodaj ABS roznicy stopni do DD
1921            temp = m_aDegrees[1 - m_iSmaller][i][1] -
1922                    m_aDegrees[ m_iSmaller ][ iMatchedPart ][1];
1923            m_iDD += abs(temp);
1924            // dodaj ABS roznicy neuronow do DN
1925            temp = m_aDegrees[1 - m_iSmaller][i][3] -
1926                    m_aDegrees[ m_iSmaller ][ iMatchedPart ][3];
1927            m_iDN += abs(temp);
1928            // pobierz polozenie dopasowanego Part
1929            Pt3D MatchedPartPos(m_aPositions[ m_iSmaller ][ iOrgMatchedPart ]);
1930            // dodaj euklidesowa odleglosc Parts do sumy odleglosci
1931            //no need to compute distane when m_dDG weight is 0
1932            m_dDG +=m_adFactors[3] == 0 ? 0 :  m_aPositions[ 1 - m_iSmaller ][ iOrgPart ].distanceTo(MatchedPartPos);
1933        }
1934    }
1935
1936    // obliczenie i dodanie różnicy w liczbie neuronów OnJoint...
1937    temp = m_aOnJoint[0][3] - m_aOnJoint[1][3];
1938    m_iDN += abs(temp);
1939    DB(printf("OnJoint DN: %i\n", abs(temp));)
1940    // ... i Anywhere
1941    temp = m_aAnywhere[0][3] - m_aAnywhere[1][3];
1942    m_iDN += abs(temp);
1943    DB(printf("Anywhere DN: %i\n", abs(temp));)
1944
1945    return 1;
1946}
1947
1948/** Computes new positions of Parts of both of organisms stored in the object.
1949        Assumptions:
1950        - models (m_Mod) are created and valid
1951        - positions (m_aPositions) are created and filled with original positions of Parts
1952        - the sorting algorithm was not yet run on the array m_aDegrees
1953        @return true if successful; false otherwise
1954 */
1955bool ModelSimil::ComputePartsPositionsBySVD()
1956{
1957    bool bResult = true; // the result; assume a success
1958
1959    // check assumptions
1960    // the models
1961    assert(m_Mod[0] != NULL && m_Mod[0]->isValid());
1962    assert(m_Mod[1] != NULL && m_Mod[1]->isValid());
1963    // the position arrays
1964    assert(m_aPositions[0] != NULL);
1965    assert(m_aPositions[1] != NULL);
1966
1967    int iMod; // a counter of models
1968    // use SVD to obtain different point of view on organisms
1969    // and store the new positions (currently the original ones are still stored)
1970    for (iMod = 0; iMod < 2; iMod++)
1971    {
1972        // prepare the vector of errors of approximation for the SVD
1973        std::vector<double> vEigenvalues;
1974        int nSize = m_Mod[ iMod ]->getPartCount();
1975
1976        double *pDistances = (double *) malloc(nSize * nSize * sizeof (double));
1977
1978        for (int i = 0; i < nSize; i++)
1979        {
1980            pDistances[i] = 0;
1981        }
1982
1983        Model *pModel = m_Mod[ iMod ]; // use the model of the iMod (current) organism
1984        int iP1, iP2; // indices of Parts in the model
1985        Part *P1, *P2; // pointers to Parts
1986        Pt3D P1Pos, P2Pos; // positions of parts
1987        double dDistance; // the distance between Parts
1988        for (iP1 = 0; iP1 < pModel->getPartCount(); iP1++)
1989        {
1990            // for each iP1, a Part index in the model of organism iMod
1991            P1 = pModel->getPart(iP1);
1992            // get the position of the Part
1993            P1Pos = P1->p;
1994            for (iP2 = 0; iP2 < pModel->getPartCount(); iP2++)
1995            {
1996                // for each (iP1, iP2), a pair of Parts index in the model
1997                P2 = pModel->getPart(iP2);
1998                // get the position of the Part
1999                P2Pos = P2->p;
2000                // compute the geometric (Euclidean) distance between the Parts
2001                dDistance = P1Pos.distanceTo(P2Pos);
2002                // store the distance
2003                pDistances[iP1 * nSize + iP2] = dDistance;
2004            } // for (iP2)
2005        } // for (iP1)
2006
2007        MatrixTools::SVD(vEigenvalues, nSize, pDistances, m_aPositions[ iMod ]);
2008        free(pDistances);
2009    }
2010
2011    return bResult;
2012}
2013
2014void ModelSimil::p_evaldistance(ExtValue *args, ExtValue *ret)
2015{
2016    Geno *g1 = GenoObj::fromObject(args[1]);
2017    Geno *g2 = GenoObj::fromObject(args[0]);
2018    if ((!g1) || (!g2))
2019        ret->setEmpty();
2020    else
2021        ret->setDouble(EvaluateDistance(g1, g2));
2022}
Note: See TracBrowser for help on using the repository browser.