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

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

SimilMeasure? -> SimilMeasureBase?; introduced a new class (SimilMeasure?) that allows scripts to access all similarity measures; a number of minor fixes and improvements

File size: 6.3 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                { "Similarity: hungarian", 1, 7, "SimilMeasureHungarian", "Evaluates morphological dissimilarity using hungarian measure. More information:\nhttp://www.framsticks.com/bib/Komosinski-et-al-2001\nhttp://www.framsticks.com/bib/Komosinski-and-Kubiak-2011\nhttp://www.framsticks.com/bib/Komosinski-2016\nhttps://doi.org/10.1007/978-3-030-16692-2_8", },
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
72void SimilMeasureHungarian::beforeTransformation()
73{
74        temp_parts_distances = new double[nBigger*nBigger]();
75        std::copy(parts_distances, parts_distances + nBigger * nBigger, temp_parts_distances);
76}
77
78double SimilMeasureHungarian::distanceForTransformation()
79{
80        fillPartsDistances(temp_parts_distances, nBigger, nSmaller, true);
81        std::fill_n(assignment, nBigger, 0);
82        double distance = hungarian.Solve(temp_parts_distances, assignment, nBigger, nBigger);
83
84        delete[] temp_parts_distances;
85        return addNeuronsPartsDiff(distance);
86}
87
88double SimilMeasureHungarian::distanceWithoutAlignment()
89{
90        double distance = hungarian.Solve(parts_distances, assignment, nBigger, nBigger);
91        if (save_matching)
92                copyMatching();
93        return addNeuronsPartsDiff(distance);
94}
95
96double SimilMeasureHungarian::addNeuronsPartsDiff(double dist)
97{
98        //add difference in anywhere and onJoint neurons
99        dist += m_adFactors[2] * (abs(on_joint[0] - on_joint[1]) + abs(anywhere[0] - anywhere[1]));
100        //add difference in part numbers
101        dist += (nBigger - nSmaller) * m_adFactors[0];
102        return dist;
103}
104
105void SimilMeasureHungarian::copyMatching()
106{
107        min_assignment.clear();
108        min_assignment.insert(min_assignment.begin(), assignment, assignment + nBigger);
109}
110
111void SimilMeasureHungarian::cleanData()
112{
113        for (int i = 0; i < 2; i++)
114        {
115                // delete degree and position arrays
116                SAFEDELETEARRAY(degrees[i]);
117                SAFEDELETEARRAY(neurons[i]);   
118
119                on_joint[i] = 0;
120                anywhere[i] = 0;       
121        }
122
123        delete[] assignment;
124        delete[] parts_distances;
125       
126        if (save_matching)
127                min_assignment.clear();
128}
129
130void SimilMeasureHungarian::countDegrees()
131{
132        Part *P1, *P2;
133        int i, j, i1, i2;
134
135        for (i = 0; i < 2; i++)
136        {
137                for (j = 0; j < models[i]->getJointCount(); j++)
138                {
139                        Joint *J = models[i]->getJoint(j);
140
141                        P1 = J->part1;
142                        P2 = J->part2;
143
144                        i1 = models[i]->findPart(P1);
145                        i2 = models[i]->findPart(P2);
146
147                        degrees[i][i1]++;
148                        degrees[i][i2]++;
149                }
150        }
151}
152
153void SimilMeasureHungarian::countNeurons()
154{
155        Part *P1;
156        Joint *J1;
157        int i, j, i2;
158
159        for (i = 0; i < 2; i++)
160        {
161                for (j = 0; j < models[i]->getNeuroCount(); j++)
162                {
163                        Neuro *N = models[i]->getNeuro(j);
164                        // count parts attached to neurons
165                        P1 = N->getPart();
166                        if (P1)
167                        {
168                                i2 = models[i]->findPart(P1);
169                                neurons[i][i2]++;
170                        }
171                        else
172                        // count unattached neurons
173                        {
174                                J1 = N->getJoint();
175                                if (J1)
176                                        on_joint[i]++;
177                                else
178                                        anywhere[i]++;
179                        }
180                }
181        }
182}
183
184void SimilMeasureHungarian::fillPartsDistances(double*& dist, int bigger, int smaller, bool geo)
185{
186        for (int i = 0; i < bigger; i++)
187        {
188                for (int j = 0; j < bigger; j++)
189                {
190                        // assign penalty for unassignment for vertex from bigger model
191                        if (j >= smaller)
192                        {
193                                if (geo)
194                                        dist[i*bigger + j] += m_adFactors[3] * coordinates[1 - m_iSmaller][i].length();
195                                else
196                                        dist[i*bigger + j] = m_adFactors[1] * degrees[1 - m_iSmaller][i] + m_adFactors[2] * neurons[1 - m_iSmaller][i];
197                        }
198                        // compute distance between parts
199                        else
200                        {
201                                if (geo){
202                                        dist[i*bigger + j] += m_adFactors[3] * coordinates[1 - m_iSmaller][i].distanceTo(coordinates[m_iSmaller][j]);
203        }
204                                else
205                                        dist[i*bigger + j] = m_adFactors[1] * abs(degrees[1 - m_iSmaller][i] - degrees[m_iSmaller][j])
206                                        + m_adFactors[2] * abs(neurons[1 - m_iSmaller][i] - neurons[m_iSmaller][j]);
207                        }
208                }
209        }
210}
211
212/** Returns number of factors involved in final distance computation.
213                These factors include differences in numbers of parts, degrees,
214                number of neurons.
215                */
216int SimilMeasureHungarian::getNOFactors()
217{
218        return SimilMeasureHungarian::iNOFactors;
219}
220
221int SimilMeasureHungarian::setParams(std::vector<double> params)
222{
223        int i = 0;
224        for (i = 0; i < SimilMeasureHungarian::iNOFactors; i++)
225                m_adFactors[i] = params.at(i);
226        fixedZaxis = params.at(i);
227        return 0;
228}
Note: See TracBrowser for help on using the repository browser.