ScorerManager.cpp
#include "ScorerManager.h"
#include "../topo-blend/topo-blend.h"
#include "Scheduler.h"
#include "GlobalReflectionSymmScorer.h"
#include "PairRelationDetector.h"
#include "ConnectivityScorer.h"
//#include "PairRelationScorer.h"
#include "GroupRelationScorer.h"
QTextStream& operator << (QTextStream& os, const ScorerManager::PathScore& pr)
{
os << "Min connectivity " << pr.connectivity.minCoeff() << "\n";
os << "Min localSymmetry " << pr.localSymmetry.minCoeff() << "\n";
os << "Min globalSymmetry " << pr.globalSymmetry.minCoeff() << "\n";
//int N = pr.connectivity.size();
//os << "Connectivity \n";
//for(int i = 0; i < N; ++i)
//{
// os << pr.connectivity[i] << "\n";
//}
//os << "local symm \n";
//for(int i = 0; i < N; ++i)
//{
// os << pr.localSymmetry[i] << "\n";
//}
//os << "global symm \n";
//for(int i = 0; i < N; ++i)
//{
// os << pr.globalSymmetry[i] << "\n";
//}
return os;
}
void saveScore(QString filename, QVector<double> scores, QString headline)
{
QFile file(filename);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) return;
QTextStream out(&file);
if ( !headline.isEmpty() )
out << headline;
int size = scores.size();
out << size << "\n";
for (int i = 0; i < size; ++i)
{
out << scores[i] << "\n";
}
file.close();
}
ScorerManager::ScorerManager( GraphCorresponder * graph_corresponder,
Scheduler * scheduler, QVector<Structure::Graph*> input_graphs, int logLevel )
{
this->logLevel_ = logLevel;
this->isUseSourceCenter_ = false;
this->isUseLink_ = false;
this->bUsePart_ = true;
init( graph_corresponder, scheduler, input_graphs);
}
void ScorerManager::init(GraphCorresponder * graph_corresponder, Scheduler * scheduler, QVector<Structure::Graph*> input_graphs)
{
this->gcorr_ = graph_corresponder;
this->scheduler_ = scheduler;
this->normalizeCoef_ = 0.0;
for ( int i = 0; i < input_graphs.size(); ++i)
{
this->actualInputGraphs_.push_back(Structure::Graph::actualGraph( input_graphs[i] ));
normalizeCoef_ += this->actualInputGraphs_[i]->bbox().diagonal().norm();
}
normalizeCoef_ *= 0.5;
maxGlobalSymmScore_ = -1;
}
void ScorerManager::parseConstraintPair()
{
emit( message("Parse constraint pair starts: ") );
this->connectPairs_.clear(); this->otherPairs_.clear();
for ( int i = 0; i < this->actualInputGraphs_.size(); ++i)
{
PairRelationDetector cpd(this->actualInputGraphs_[i], i, normalizeCoef_, this->isUseLink_, true, logLevel_);
cpd.detect(this->actualInputGraphs_[(i+1)%this->actualInputGraphs_.size()], this->gcorr_->correspondences);
this->connectPairs_.push_back(cpd.connectedPairs_);
this->otherPairs_.push_back(cpd.otherPairs_);
if (this->logLevel_)
{
saveToFile("pair_relation-" + QString::number(i) + ".txt", cpd.otherPairs_);
}
}
emit( message("Parse constraint pairs end. ") );
}
void ScorerManager::evaluateTopology()
{
/////////////////
emit( message("Evaluate topology starts: ") );
if ( connectPairs_.empty() )
{
emit( message("Parse topology first! ") );
return;
}
int idx(0);
Structure::Graph* g = getCurrentGraph(idx);
ConnectivityScorer cs(g, idx, this->normalizeCoef_, this->isUseLink_, this->logLevel_);
cs.evaluate(this->connectPairs_, this->gcorr_->correspondences);
emit( message("Evaluate topology end. ") );
}
QVector<double> ScorerManager::evaluateTopology( QVector<Structure::Graph*> const &graphs )
{
QVector<double> topoScore;
int logLevel = 0;
double score;
for (int i = 0; i < graphs.size(); ++i)
{
Structure::Graph * g = Structure::Graph::actualGraph(graphs[i] );
ConnectivityScorer cs(g, i, this->normalizeCoef_, this->isUseLink_, logLevel);
score = cs.evaluate(this->connectPairs_, this->gcorr_->correspondences);
topoScore.push_back(score);
}
return topoScore;
}
void ScorerManager::evaluateTopologyAuto()
{
emit( message("Evaluate topology auto starts: ") );
if ( connectPairs_.empty() )
{
emit( message("Parse topology first! ") );
return;
}
QVector<double> topoScore = evaluateTopology(this->scheduler_->allGraphs);
saveScore(QString("evaluate_connectivity_auto.txt"), topoScore, QString());
emit( message("Evaluate topology auto end. ") );
}
void ScorerManager::parseConstraintGroup()
{
//////////////////
emit( message("Parse constraint group starts: ") );
if ( this->otherPairs_.size() < 2)
{
emit( message("Parse pairs first!") );
return;
}
///////////////////////
groupRelations_.clear();
for ( int i = 0; i < this->actualInputGraphs_.size(); ++i)
{
Structure::Graph * g = Structure::Graph::actualGraph( this->actualInputGraphs_[i] );
GroupRelationDetector grd(g, i, this->normalizeCoef_, this->logLevel_);
grd.detect(this->otherPairs_[i]);
this->groupRelations_.push_back(grd.groupRelations_);
if (this->logLevel_)
{
saveToFile("group_relation-" + QString::number(i) + ".txt", this->groupRelations_[i]);
saveToFile("pair_relation-" + QString::number(i) + ".txt", this->otherPairs_[i]);
}
}
emit( message("Parse constraint group end. ") );
}
void ScorerManager::evaluateGroups()
{
/////////////////
emit( message("Evaluate group starts: ") );
if ( this->groupRelations_.empty() )
{
emit( message("Parse constraint group first! ") );
return;
}
int idx(0);
Structure::Graph* g = getCurrentGraph(idx);
GroupRelationScorer grs(g, idx, this->normalizeCoef_, this->logLevel_);
grs.evaluate(groupRelations_, this->gcorr_->correspondences);
emit( message("Evaluate group end. ") );
}
QVector<double> ScorerManager::evaluateGroups( QVector<Structure::Graph*> const &graphs )
{
QVector<double> groupScore;
int logLevel = 0;
double score;
for (int i = 0; i < graphs.size(); ++i)
{
Structure::Graph * g = Structure::Graph::actualGraph(graphs[i] );
GroupRelationScorer grs(g, i, this->normalizeCoef_, logLevel);
score = grs.evaluate(groupRelations_, this->gcorr_->correspondences);
groupScore.push_back(score);
}
return groupScore;
}
void ScorerManager::evaluateGroupsAuto()
{
emit( message("Evaluate group auto starts: ") );
if ( groupRelations_.empty() )
{
emit( message("Parse constraint group first! ") );
return;
}
QVector<double> groupScore = evaluateGroups(this->scheduler_->allGraphs);
saveScore(QString("evaluate_group_auto.txt"), groupScore, QString());
emit( message("Evaluate group auto end. ") );
return;
}
void ScorerManager::parseGlobalReflectionSymm()
{
//////////////////
emit( message("Parse global symmetry starts: ") );
if ( this->actualInputGraphs_.size() < 2)
{
emit( ("Two graphs needed!") );
return;
}
double symmScore[2];
for (int i = 0; i < this->actualInputGraphs_.size(); ++i)
{
Structure::Graph * g = Structure::Graph::actualGraph( this->actualInputGraphs_[i] );
GlobalReflectionSymmScorer gss(g, i, this->normalizeCoef_, this->bUsePart_, this->logLevel_);
symmScore[i] = gss.evaluate();
if ( i == 0)
{
this->refCenter_ = gss.center_;
this->refNormal_ = gss.normal_;
}
}
this->maxGlobalSymmScore_ = std::max(symmScore[0], symmScore[1]);
//this->maxGlobalSymmScore_ = symmScore[0];
emit( message("Parse global symmetry end. ") );
}
void ScorerManager::evaluateGlobalReflectionSymm()
{
/////////////////
emit( message("Evaluate global symmetry starts: ") );
if ( !isGlobalReflectionSymmParsed() )
{
emit( message("Parse global symmetry first! ") );
return;
}
int idx(0);
Structure::Graph* g = getCurrentGraph(idx);
GlobalReflectionSymmScorer gss(g, idx, this->normalizeCoef_, this->bUsePart_, this->logLevel_);
double symmScore;
if (isUseSourceCenter_)
symmScore = gss.evaluate( this->refCenter_, this->refNormal_, this->maxGlobalSymmScore_);
else
symmScore = gss.evaluate( gss.center_, this->refNormal_, this->maxGlobalSymmScore_);
emit( message("Evaluate global symmetry end. ") );
}
QVector<double> ScorerManager::evaluateGlobalReflectionSymm( QVector<Structure::Graph*> const &graphs )
{
QVector<double> symmScore;
int logLevel = 0;
double score;
for (int i = 0; i < graphs.size(); ++i)
{
Structure::Graph * g = Structure::Graph::actualGraph(graphs[i] );
GlobalReflectionSymmScorer gss(g, i, this->normalizeCoef_, this->bUsePart_, logLevel);
if (isUseSourceCenter_)
score = gss.evaluate( this->refCenter_, this->refNormal_, this->maxGlobalSymmScore_);
else
score = gss.evaluate( gss.center_, this->refNormal_, this->maxGlobalSymmScore_);
symmScore.push_back(score);
}
return symmScore;
}
void ScorerManager::evaluateGlobalReflectionSymmAuto()
{
///////////////// pre-condition
emit( message("Evaluate global symmetry auto starts: ") );
if ( !isGlobalReflectionSymmParsed() )
{
emit( message("Parse global symmetry first! ") );
return;
}
///////////////// compute
QVector<double> symmScore = evaluateGlobalReflectionSymm(this->scheduler_->allGraphs);
QString headline = "is use source center: ";
if ( isUseSourceCenter_)
{
headline.append("true");
}
else
{
headline.append("false");
}
headline.append("\n");
saveScore(QString("evaluate_global_symm_auto.txt"), symmScore, headline);
emit( message("Evaluate global symmetry auto end. ") );
}
void ScorerManager::setIsUseSourceCenter(bool bUse)
{
isUseSourceCenter_ = bUse;
if (isUseSourceCenter_)
emit( message("use source center") );
else
emit( message("not use source center") );
}
void ScorerManager::setIsUsePart(bool bUse)
{
this->bUsePart_ = bUse;
if (bUsePart_)
emit( message("use part for global symm") );
else
emit( message("not use part for global symm") );
}
void ScorerManager::setIsUseLink(bool bUse)
{
isUseLink_ = bUse;
if (isUseLink_)
emit( message("use link for connectivity") );
else
emit( message("not link for connectivity") );
}
Structure::Graph * ScorerManager::getCurrentGraph(int& idx)
{
int ct = this->scheduler_->slider->currentTime();
idx = this->scheduler_->allGraphs.size() * (double(ct) / this->scheduler_->totalExecutionTime());
Structure::Graph * g = Structure::Graph::actualGraph(this->scheduler_->allGraphs[idx]);
return g;
}
ScorerManager::PathScore ScorerManager::pathScore( QVector<Structure::Graph*> graphs )
{
ScorerManager::PathScore score;
int N = graphs.size();
int logLevel = 0;
QVector<double> connectivity, localSymmetry, globalSymmetry;
// Compute all scores at once
for (int i = 0; i < N; ++i)
{
Structure::Graph * g = Structure::Graph::actualGraph(graphs[i] );
// Connectivity
ConnectivityScorer cs(g, i, this->normalizeCoef_, this->isUseLink_, logLevel);
connectivity.push_back( cs.evaluate(this->connectPairs_, this->gcorr_->correspondences) );
// Local symmetry
GroupRelationScorer grs(g, i, this->normalizeCoef_, logLevel);
localSymmetry.push_back( grs.evaluate(groupRelations_, this->gcorr_->correspondences) );
// Global symmetry
GlobalReflectionSymmScorer gss(g, i, this->normalizeCoef_, logLevel);
if (isUseSourceCenter_)
globalSymmetry.push_back( gss.evaluate( this->refCenter_, this->refNormal_, this->maxGlobalSymmScore_) );
else
globalSymmetry.push_back( gss.evaluate( gss.center_, this->refNormal_, this->maxGlobalSymmScore_) );
// Clean up
delete g;
}
// Fill scores into vectors
score.connectivity = VectorXd::Zero(N);
score.localSymmetry = VectorXd::Zero(N);
score.globalSymmetry = VectorXd::Zero(N);
for(int i = 0; i < N; i++)
{
score.connectivity[i] = connectivity[i];
score.localSymmetry[i] = localSymmetry[i];
score.globalSymmetry[i] = globalSymmetry[i];
graphs[i]->property["scoreConnectivity"] = 1 - connectivity[i];
graphs[i]->property["scoreSymLocal"] = 1 - localSymmetry[i];
graphs[i]->property["scoreSymGlobal"] = 1 - globalSymmetry[i];
double error = qMax(qMax(connectivity[i], localSymmetry[i]), globalSymmetry[i]);
graphs[i]->property["score"] = -error;
}
return score;
}
MatrixXd ScorerManager::PathScore::computeRange()
{
// Columns: min, max, range, average
MatrixXd R(3, 4);
R(0,0) = connectivity.minCoeff(); R(0,1) = connectivity.maxCoeff(); R(0,2) = R(0,1) - R(0,0); R(0,3) = connectivity.mean();
R(1,0) = localSymmetry.minCoeff(); R(1,1) = localSymmetry.maxCoeff(); R(1,2) = R(1,1) - R(1,0); R(1,3) = localSymmetry.mean();
R(2,0) = globalSymmetry.minCoeff(); R(2,1) = globalSymmetry.maxCoeff(); R(2,2) = R(2,1) - R(2,0); R(2,3) = globalSymmetry.mean();
return R;
}
double ScorerManager::PathScore::score()
{
int N = connectivity.size();
double errConnect = 0, errLocal = 0, errSymmetry = 0;
for(int i = 0; i < N; i++)
{
errConnect += 1.0 - connectivity[i];
errLocal += 1.0 - localSymmetry[i];
errSymmetry += 1.0 - globalSymmetry[i];
}
double error = qMax(qMax(errConnect, errLocal), errSymmetry);
return -error;
}