Commit ddb5ccb5 authored by Anton Gladky's avatar Anton Gladky
Browse files

Replace vector by unordered_map data structure in Matchmaker.

It allows to search for colliding coefficients much faster
than using a simple vector which is getting extremely slow
with the large number of coefficients.
parent e5429c72
......@@ -5,12 +5,21 @@
YADE_PLUGIN((MatchMaker));
Real MatchMaker::operator()(int id1, int id2, Real val1, Real val2) const {
FOREACH(const Vector3r& m, matches){
if(((int)m[0]==id1 && (int)m[1]==id2) || ((int)m[0]==id2 && (int)m[1]==id1)) return m[2];
const int minId = std::min(id1, id2);
const int maxId = std::max(id2, id2);
const auto foundMatchItem = matchSet.find (std::make_pair(minId, maxId));
if ( foundMatchItem != matchSet.end() ) {
return foundMatchItem->second;
} else {
if(fbNeedsValues && (std::isnan(val1) || std::isnan(val2))) {
throw std::invalid_argument("MatchMaker: no match for ("+boost::lexical_cast<string>(id1)+
","+boost::lexical_cast<string>(id2)+"), and values required for algo computation '"+
algo+"' not specified.");
}
return computeFallback(val1,val2);
}
// no match
if(fbNeedsValues && (std::isnan(val1) || std::isnan(val2))) throw std::invalid_argument("MatchMaker: no match for ("+boost::lexical_cast<string>(id1)+","+boost::lexical_cast<string>(id2)+"), and values required for algo computation '"+algo+"' not specified.");
return computeFallback(val1,val2);
}
void MatchMaker::postLoad(MatchMaker&){
......@@ -21,6 +30,14 @@ void MatchMaker::postLoad(MatchMaker&){
else if(algo=="max") { fbPtr=&MatchMaker::fbMax; fbNeedsValues=true; }
else if(algo=="harmAvg") { fbPtr=&MatchMaker::fbHarmAvg; fbNeedsValues=true; }
else throw std::invalid_argument("MatchMaker:: algo '"+algo+"' not recognized (possible values: val, avg, min, max, harmAvg).");
// Fill matchSet with values for a fast coefficient search
for (const auto & m : matches) {
const int minId = std::min((int)m[0], (int)m[1]);
const int maxId = std::max((int)m[0], (int)m[1]);
const auto idPair = std::make_pair(minId, maxId);
matchSet.insert(std::make_pair(idPair, m[2]));
}
}
Real MatchMaker::computeFallback(Real v1, Real v2) const { return (this->*MatchMaker::fbPtr)(v1,v2); }
// 2010 © Václav Šmilauer <eudoxos@arcig.cz>
#pragma once
#include<lib/serialization/Serializable.hpp>
#include <lib/serialization/Serializable.hpp>
#include <boost/unordered_map.hpp>
namespace py = boost::python;
......@@ -11,7 +12,6 @@ namespace py = boost::python;
*/
class MatchMaker: public Serializable {
#if 1
Real fbZero(Real v1, Real v2) const{ return 0.; }
Real fbAvg(Real v1, Real v2) const{ return (v1+v2)/2.; }
Real fbMin(Real v1, Real v2) const{ return min(v1,v2); }
......@@ -22,7 +22,10 @@ class MatchMaker: public Serializable {
// whether the current fbPtr function needs valid input values in order to give meaningful result.
// must be kept in sync with fbPtr, which is done in postLoad
bool fbNeedsValues;
#endif
// unordered set for a fast coefficient search
boost::unordered_map<std::pair<int, int>, Real> matchSet;
public:
virtual ~MatchMaker() {};
MatchMaker(std::string _algo): algo(_algo){ postLoad(*this); }
......@@ -34,7 +37,7 @@ class MatchMaker: public Serializable {
// if no match is found and val1 or val2 are not given, throw exception
Real operator()(const int id1, const int id2, const Real val1=NaN, const Real val2=NaN) const;
YADE_CLASS_BASE_DOC_ATTRS_CTOR_PY(MatchMaker,Serializable,"Class matching pair of ids to return pre-defined (for a pair of ids defined in :yref:`matches<MatchMaker.matches>`) or derived value (computed using :yref:`algo<MatchMaker.algo>`) of a scalar parameter. It can be called (``id1``, ``id2``, ``val1=NaN``, ``val2=NaN``) in both python and c++. \n\n.. note:: There is a :ref:`converter <customconverters>` from python number defined for this class, which creates a new :yref:`MatchMaker` returning the value of that number; instead of giving the object instance therefore, you can only pass the number value and it will be converted automatically.",
((std::vector<Vector3r>,matches,,,"Array of ``(id1,id2,value)`` items; queries matching ``id1`` + ``id2`` or ``id2`` + ``id1`` will return ``value``"))
((std::vector<Vector3r>,matches,,Attr::readonly,"Array of ``(id1,id2,value)`` items; queries matching ``id1`` + ``id2`` or ``id2`` + ``id1`` will return ``value``"))
((std::string,algo,"avg",Attr::triggerPostLoad,"Alogorithm used to compute value when no match for ids is found. Possible values are\n\n* 'avg' (arithmetic average)\n* 'min' (minimum value)\n* 'max' (maximum value)\n* 'harmAvg' (harmonic average)\n\nThe following algo algorithms do *not* require meaningful input values in order to work:\n\n* 'val' (return value specified by :yref:`val<MatchMaker.val>`)\n* 'zero' (always return 0.)\n\n"))
((Real,val,NaN,,"Constant value returned if there is no match and :yref:`algo<MatchMaker::algo>` is ``val``"))
, fbPtr=&MatchMaker::fbAvg; fbNeedsValues=true; /* keep in sync with the algo value for algo */
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment