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

Last change on this file since 606 was 606, checked in by Maciej Komosinski, 8 years ago

Code formatting

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