source: cpp/frams/model/similarity/measure-hungarian.cpp @ 1326

Last change on this file since 1326 was 1174, checked in by Maciej Komosinski, 3 years ago

Cosmetic

File size: 6.5 KB
Line 
1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
2// Copyright (C) 1999-2020  Maciej Komosinski and Szymon Ulatowski.
3// See LICENSE.txt for details.
4
5#include "measure-hungarian.h"
6
7const int SimilMeasureHungarian::iNOFactors = 4;
8
9#define FIELDSTRUCT SimilMeasureHungarian
10
11static ParamEntry simil_hungarian_paramtab[] = {
12                { "Creature: Similarity: Graph optimal", 1, 7, "SimilMeasureHungarian", "Evaluates morphological dissimilarity using the measure. More information:\nhttp://www.framsticks.com/bib/Komosinski-et-al-2001\nhttp://www.framsticks.com/bib/Komosinski-and-Kubiak-2011\nhttp://www.framsticks.com/bib/Komosinski-2016\nhttps://www.framsticks.com/bib/Komosinski-and-Mensfelt-2019", },
13                { "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.", },
14                { "simil_partdeg", 0, 0, "Weight of parts' degree", "f 0 100 1", FIELD(m_adFactors[1]), "", },
15                { "simil_neuro", 0, 0, "Weight of neurons count", "f 0 100 0.1", FIELD(m_adFactors[2]), "", },
16                { "simil_partgeom", 0, 0, "Weight of parts' geometric distances", "f 0 100 0", FIELD(m_adFactors[3]), "", },
17                { "simil_fixedZaxis", 0, 0, "Fix 'z' (vertical) axis?", "d 0 1 0", FIELD(fixedZaxis), "", },
18                { "simil_weightedMDS", 0, 0, "Should weighted MDS be used?", "d 0 1 0", FIELD(wMDS), "If activated, weighted MDS with vertex (i.e., Part) degrees as weights is used for 3D alignment of body structure.", },
19                { "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.", },
20                { 0, },
21};
22
23#undef FIELDSTRUCT
24
25SimilMeasureHungarian::SimilMeasureHungarian() : localpar(simil_hungarian_paramtab, this)
26{
27        localpar.setDefault();
28       
29        nSmaller = 0;
30        nBigger = 0;
31       
32        for (int i = 0; i < 2; i++)
33        {
34                degrees[i] = nullptr;
35                neurons[i] = nullptr;
36                on_joint[i] = 0;
37                anywhere[i] = 0;       
38        }
39       
40        assignment = nullptr;
41        parts_distances = nullptr;
42        temp_parts_distances = nullptr;
43       
44        save_matching = false;
45}
46
47void SimilMeasureHungarian::prepareData()
48{
49        m_iSmaller = models[0]->getPartCount() <= models[1]->getPartCount() ? 0 : 1;
50        nSmaller = models[m_iSmaller]->getPartCount();
51        nBigger = models[1 - m_iSmaller]->getPartCount();
52
53        for (int i = 0; i < 2; i++)
54        {
55                int size = models[i]->getPartCount();
56                degrees[i] = new int[size]();
57                neurons[i] = new int[size]();
58        }
59       
60        countDegrees();
61        countNeurons();
62       
63        parts_distances = new double[nBigger*nBigger]();
64        fillPartsDistances(parts_distances, nBigger, nSmaller, false);
65        assignment = new int[nBigger]();
66       
67        if (save_matching)
68                for (int i = 0; i < nBigger; i++)
69                        min_assignment.push_back(0);
70       
71        if (m_adFactors[3] == 0)
72            with_alignment = false;
73}
74
75void SimilMeasureHungarian::beforeTransformation()
76{
77        temp_parts_distances = new double[nBigger*nBigger]();
78        std::copy(parts_distances, parts_distances + nBigger * nBigger, temp_parts_distances);
79}
80
81double SimilMeasureHungarian::distanceForTransformation()
82{
83        fillPartsDistances(temp_parts_distances, nBigger, nSmaller, true);
84        std::fill_n(assignment, nBigger, 0);
85        double distance = hungarian.Solve(temp_parts_distances, assignment, nBigger, nBigger);
86
87        delete[] temp_parts_distances;
88        return addNeuronsPartsDiff(distance);
89}
90
91double SimilMeasureHungarian::distanceWithoutAlignment()
92{
93        double distance = hungarian.Solve(parts_distances, assignment, nBigger, nBigger);
94        if (save_matching)
95                copyMatching();
96        return addNeuronsPartsDiff(distance);
97}
98
99double SimilMeasureHungarian::addNeuronsPartsDiff(double dist)
100{
101        //add difference in anywhere and onJoint neurons
102        dist += m_adFactors[2] * (abs(on_joint[0] - on_joint[1]) + abs(anywhere[0] - anywhere[1]));
103        //add difference in part numbers
104        dist += (nBigger - nSmaller) * m_adFactors[0];
105        return dist;
106}
107
108void SimilMeasureHungarian::copyMatching()
109{
110        min_assignment.clear();
111        min_assignment.insert(min_assignment.begin(), assignment, assignment + nBigger);
112}
113
114void SimilMeasureHungarian::cleanData()
115{
116        for (int i = 0; i < 2; i++)
117        {
118                // delete degree and position arrays
119                SAFEDELETEARRAY(degrees[i]);
120                SAFEDELETEARRAY(neurons[i]);   
121
122                on_joint[i] = 0;
123                anywhere[i] = 0;       
124        }
125
126        delete[] assignment;
127        delete[] parts_distances;
128       
129        if (save_matching)
130                min_assignment.clear();
131       
132        with_alignment = true; //restore default value
133}
134
135void SimilMeasureHungarian::countDegrees()
136{
137        Part *P1, *P2;
138        int i, j, i1, i2;
139
140        for (i = 0; i < 2; i++)
141        {
142                for (j = 0; j < models[i]->getJointCount(); j++)
143                {
144                        Joint *J = models[i]->getJoint(j);
145
146                        P1 = J->part1;
147                        P2 = J->part2;
148
149                        i1 = models[i]->findPart(P1);
150                        i2 = models[i]->findPart(P2);
151
152                        degrees[i][i1]++;
153                        degrees[i][i2]++;
154                }
155        }
156}
157
158void SimilMeasureHungarian::countNeurons()
159{
160        Part *P1;
161        Joint *J1;
162        int i, j, i2;
163
164        for (i = 0; i < 2; i++)
165        {
166                for (j = 0; j < models[i]->getNeuroCount(); j++)
167                {
168                        Neuro *N = models[i]->getNeuro(j);
169                        // count parts attached to neurons
170                        P1 = N->getPart();
171                        if (P1)
172                        {
173                                i2 = models[i]->findPart(P1);
174                                neurons[i][i2]++;
175                        }
176                        else
177                        // count unattached neurons
178                        {
179                                J1 = N->getJoint();
180                                if (J1)
181                                        on_joint[i]++;
182                                else
183                                        anywhere[i]++;
184                        }
185                }
186        }
187}
188
189void SimilMeasureHungarian::fillPartsDistances(double*& dist, int bigger, int smaller, bool geo)
190{
191        for (int i = 0; i < bigger; i++)
192        {
193                for (int j = 0; j < bigger; j++)
194                {
195                        // assign penalty for unassignment for vertex from bigger model
196                        if (j >= smaller)
197                        {
198                                if (geo)
199                                        dist[i*bigger + j] += m_adFactors[3] * coordinates[1 - m_iSmaller][i].length();
200                                else
201                                        dist[i*bigger + j] = m_adFactors[1] * degrees[1 - m_iSmaller][i] + m_adFactors[2] * neurons[1 - m_iSmaller][i];
202                        }
203                        // compute distance between parts
204                        else
205                        {
206                                if (geo){
207                                        dist[i*bigger + j] += m_adFactors[3] * coordinates[1 - m_iSmaller][i].distanceTo(coordinates[m_iSmaller][j]);
208        }
209                                else
210                                        dist[i*bigger + j] = m_adFactors[1] * abs(degrees[1 - m_iSmaller][i] - degrees[m_iSmaller][j])
211                                        + m_adFactors[2] * abs(neurons[1 - m_iSmaller][i] - neurons[m_iSmaller][j]);
212                        }
213                }
214        }
215}
216
217/** Returns number of factors involved in final distance computation.
218                These factors include differences in numbers of parts, degrees,
219                number of neurons.
220                */
221int SimilMeasureHungarian::getNOFactors()
222{
223        return SimilMeasureHungarian::iNOFactors;
224}
225
226int SimilMeasureHungarian::setParams(std::vector<double> params)
227{
228        int i = 0;
229        for (i = 0; i < SimilMeasureHungarian::iNOFactors; i++)
230                m_adFactors[i] = params.at(i);
231        fixedZaxis = params.at(i);
232        return 0;
233}
Note: See TracBrowser for help on using the repository browser.