source: src/FunctionApproximation/Extractors.cpp@ 143263

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since 143263 was e1fe7e, checked in by Frederik Heber <heber@…>, 11 years ago

FunctionModel now uses list_of_arguments to split sequence of subsets of distances.

  • this fixes ambiguities with the set of distances: Imagine the distances within a water molecule as OH (A) and HH (B). We then may have a sequence of argument_t as AABAAB. And with the current implementation of CompoundPotential::splitUpArgumentsByModels() we would always choose the latter (and more complex) model. Hence, we make two calls to TriplePotential_Angle, instead of calls twice to PairPotential_Harmonic for A, one to PairPotential_Harmonic for B, and once to TriplePotential_Angle for AAB.
  • now, we new list looks like A,A,B,AAB where each tuple of distances can be uniquely associated with a specific potential.
  • changed signatures of EmpiricalPotential::operator(), ::derivative(), ::parameter_derivative(). This involved changing all of the current specific potentials and CompoundPotential.
  • TrainingData must discern between the InputVector_t (just all distances) and the FilteredInputVector_t (tuples of subsets of distances).
  • FunctionApproximation now has list_of_arguments_t as parameter to evaluate() and evaluate_derivative().
  • DOCU: docu change in TrainingData.
  • Property mode set to 100644
File size: 31.4 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2012 University of Bonn. All rights reserved.
5 * Copyright (C) 2013 Frederik Heber. All rights reserved.
6 * Please see the COPYING file or "Copyright notice" in builder.cpp for details.
7 *
8 *
9 * This file is part of MoleCuilder.
10 *
11 * MoleCuilder is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation, either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * MoleCuilder is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with MoleCuilder. If not, see <http://www.gnu.org/licenses/>.
23 */
24
25/*
26 * Extractors.cpp
27 *
28 * Created on: 15.10.2012
29 * Author: heber
30 */
31
32// include config.h
33#ifdef HAVE_CONFIG_H
34#include <config.h>
35#endif
36
37#include "CodePatterns/MemDebug.hpp"
38
39#include <sstream>
40#include <utility>
41#include <vector>
42#include <boost/assign.hpp>
43#include <boost/bind.hpp>
44#include <boost/foreach.hpp>
45
46#include "CodePatterns/Assert.hpp"
47#include "CodePatterns/IteratorAdaptors.hpp"
48#include "CodePatterns/Log.hpp"
49#include "CodePatterns/toString.hpp"
50
51#include "LinearAlgebra/Vector.hpp"
52
53#include "FunctionApproximation/Extractors.hpp"
54#include "FunctionApproximation/FunctionArgument.hpp"
55
56using namespace boost::assign;
57
58FunctionModel::arguments_t
59Extractors::gatherAllDistanceArguments(
60 const Fragment::positions_t& positions,
61 const Fragment::charges_t& charges,
62 const size_t globalid)
63{
64 FunctionModel::arguments_t result;
65
66 // go through current configuration and gather all other distances
67 Fragment::positions_t::const_iterator firstpositer = positions.begin();
68 for (;firstpositer != positions.end(); ++firstpositer) {
69 Fragment::positions_t::const_iterator secondpositer = positions.begin();//firstpositer;
70 for (; secondpositer != positions.end(); ++secondpositer) {
71 if (firstpositer == secondpositer)
72 continue;
73 argument_t arg;
74 const Vector firsttemp((*firstpositer)[0],(*firstpositer)[1],(*firstpositer)[2]);
75 const Vector secondtemp((*secondpositer)[0],(*secondpositer)[1],(*secondpositer)[2]);
76 arg.distance = firsttemp.distance(secondtemp);
77 arg.types = std::make_pair(
78 charges[ std::distance(positions.begin(), firstpositer) ],
79 charges[ std::distance(positions.begin(), secondpositer) ]
80 );
81 arg.indices = std::make_pair(
82 std::distance(
83 positions.begin(), firstpositer),
84 std::distance(
85 positions.begin(), secondpositer)
86 );
87 arg.globalid = globalid;
88 result.push_back(arg);
89 }
90 }
91
92 return result;
93}
94
95FunctionModel::arguments_t
96Extractors::gatherAllSymmetricDistanceArguments(
97 const Fragment::positions_t& positions,
98 const Fragment::charges_t& charges,
99 const size_t globalid)
100{
101 FunctionModel::arguments_t result;
102
103 // go through current configuration and gather all other distances
104 Fragment::positions_t::const_iterator firstpositer = positions.begin();
105 for (;firstpositer != positions.end(); ++firstpositer) {
106 Fragment::positions_t::const_iterator secondpositer = firstpositer;
107 for (; secondpositer != positions.end(); ++secondpositer) {
108 if (firstpositer == secondpositer)
109 continue;
110 argument_t arg;
111 const Vector firsttemp((*firstpositer)[0],(*firstpositer)[1],(*firstpositer)[2]);
112 const Vector secondtemp((*secondpositer)[0],(*secondpositer)[1],(*secondpositer)[2]);
113 arg.distance = firsttemp.distance(secondtemp);
114 arg.types = std::make_pair(
115 charges[ std::distance(positions.begin(), firstpositer) ],
116 charges[ std::distance(positions.begin(), secondpositer) ]
117 );
118 arg.indices = std::make_pair(
119 std::distance(
120 positions.begin(), firstpositer),
121 std::distance(
122 positions.begin(), secondpositer)
123 );
124 arg.globalid = globalid;
125 LOG(3, "DEBUG: Created argument " << arg << ".");
126 result.push_back(arg);
127 }
128 }
129
130 return result;
131}
132
133Fragment::positions_t Extractors::_detail::gatherPositionsFromTargets(
134 const Fragment::positions_t& positions,
135 const Fragment::charges_t& charges,
136 const chargeiters_t &targets
137 )
138{
139 Fragment::positions_t filtered_positions;
140 for (chargeiters_t::const_iterator firstpairiter = targets.begin();
141 firstpairiter != targets.end(); ++firstpairiter) {
142 Fragment::positions_t::const_iterator positer = positions.begin();
143 const size_t steps = std::distance(charges.begin(), *firstpairiter);
144 std::advance(positer, steps);
145 filtered_positions.push_back(*positer);
146 }
147 return filtered_positions;
148}
149
150FunctionModel::arguments_t Extractors::_detail::gatherDistancesFromTargets(
151 const Fragment::positions_t& positions,
152 const Fragment::charges_t& charges,
153 const chargeiters_t &targets,
154 const size_t globalid
155 )
156{
157 Fragment::positions_t filtered_positions;
158 Fragment::charges_t filtered_charges;
159 for (chargeiters_t::const_iterator firstpairiter = targets.begin();
160 firstpairiter != targets.end(); ++firstpairiter) {
161 Fragment::positions_t::const_iterator positer = positions.begin();
162 const size_t steps = std::distance(charges.begin(), *firstpairiter);
163 std::advance(positer, steps);
164 filtered_positions.push_back(*positer);
165 filtered_charges.push_back(**firstpairiter);
166 }
167 return Extractors::gatherAllSymmetricDistanceArguments(
168 filtered_positions,
169 filtered_charges,
170 globalid);
171}
172
173Extractors::elementcounts_t
174Extractors::_detail::getElementCounts(
175 const Fragment::charges_t elements
176 )
177{
178 elementcounts_t elementcounts;
179 for (Fragment::charges_t::const_iterator elementiter = elements.begin();
180 elementiter != elements.end(); ++elementiter) {
181 // insert new element
182 std::pair< elementcounts_t::iterator, bool> inserter =
183 elementcounts.insert( std::make_pair( *elementiter, 1) );
184 // if already present, just increase its count
185 if (!inserter.second)
186 ++(inserter.first->second);
187 }
188 return elementcounts;
189}
190
191Extractors::elementtargets_t
192Extractors::_detail::convertElementcountsToTargets(
193 const Fragment::charges_t &charges,
194 const elementcounts_t &elementcounts
195 )
196{
197 elementtargets_t elementtargets;
198 for (elementcounts_t::const_iterator countiter = elementcounts.begin();
199 countiter != elementcounts.end();
200 ++countiter) {
201 chargeiter_t chargeiter = charges.begin();
202 const element_t &element = countiter->first;
203 const count_t &count = countiter->second;
204 for (count_t i = 0; i < count; ++i) {
205 chargeiter_t tempiter = std::find(chargeiter, charges.end(), element);
206 if (tempiter != charges.end()) {
207 // try to insert new list
208 std::pair< elementtargets_t::iterator, bool> inserter =
209 elementtargets.insert( std::make_pair( countiter->first, chargeiters_t(1, tempiter)) );
210 // if already present, append to it
211 if (!inserter.second) {
212 inserter.first->second.push_back(tempiter);
213 } else { // if created, increase vector's reserve to known size
214 inserter.first->second.reserve(countiter->second);
215 }
216 // search from this element onwards then
217 chargeiter = ++tempiter;
218 } else {
219 ELOG(1, "Could not find desired number " << count << " of element "
220 << element << " in fragment with " << charges << ".");
221 return Extractors::elementtargets_t();
222 }
223 }
224 }
225 return elementtargets;
226}
227
228Extractors::elementtargets_t
229Extractors::_detail::convertChargesToTargetMap(
230 const Fragment::charges_t& charges,
231 Fragment::charges_t elements
232 )
233{
234 // place each charge into a map
235 elementtargets_t completeelementtargets;
236 for (chargeiter_t chargeiter = charges.begin();
237 chargeiter != charges.end();
238 ++chargeiter) {
239 std::pair< elementtargets_t::iterator, bool> inserter =
240 completeelementtargets.insert( std::make_pair( *chargeiter, chargeiters_t(1, chargeiter)) );
241 // if already present, append to it
242 if (!inserter.second) {
243 inserter.first->second.push_back(chargeiter);
244 }
245 }
246 // pick out desired charges only
247 std::sort(elements.begin(), elements.end());
248 Fragment::charges_t::iterator eraseiter =
249 std::unique(elements.begin(), elements.end());
250 elements.erase(eraseiter, elements.end());
251 elementtargets_t elementtargets;
252 for(Fragment::charges_t::const_iterator iter = elements.begin();
253 iter != elements.end();
254 ++iter) {
255 elementtargets_t::const_iterator finditer = completeelementtargets.find(*iter);
256 ASSERT( finditer != completeelementtargets.end(),
257 "Extractors::_detail::convertChargesToTargetMap() - no element "+toString(*iter)+" present?");
258 std::pair< elementtargets_t::iterator, bool> inserter =
259 elementtargets.insert( std::make_pair( finditer->first, finditer->second) );
260 ASSERT( inserter.second,
261 "Extractors::_detail::convertChargesToTargetMap() - key twice?");
262 }
263 return elementtargets;
264}
265
266
267Extractors::chargeiters_t
268Extractors::_detail::realignElementtargets(
269 const elementtargets_t &elementtargets,
270 const Fragment::charges_t elements,
271 const elementcounts_t &elementcounts
272 )
273{
274 chargeiters_t targets;
275 elementcounts_t counts; // how many chargeiters of this element have been used
276 if (!elements.empty()) { // skip if no elements given
277 targets.reserve(elements.size());
278 for (Fragment::charges_t::const_iterator elementiter = elements.begin();
279 elementiter != elements.end(); ++elementiter) {
280 const element_t &element = *elementiter;
281 count_t &count = counts[element]; // if not present, std::map creates instances with default of 0
282#ifndef NDEBUG
283 {
284 elementcounts_t::const_iterator testiter = elementcounts.find(element);
285 ASSERT( (testiter != elementcounts.end()) && (count < testiter->second),
286 "Extractors::_detail::realignElementTargets() - we want to use more chargeiters for element "
287 +toString(element)+" than we counted initially.");
288 }
289#endif
290 elementtargets_t::const_iterator targetiter = elementtargets.find(element);
291 if (targetiter != elementtargets.end()) {
292 const chargeiters_t &chargeiters = targetiter->second;
293 const chargeiter_t &chargeiter = chargeiters[count++];
294 targets.push_back(chargeiter);
295 }
296 }
297 }
298 return targets;
299}
300
301FunctionModel::arguments_t
302Extractors::gatherAllDistancesFromFragment(
303 const Fragment::positions_t& positions,
304 const Fragment::charges_t& charges,
305 const Fragment::charges_t elements,
306 const size_t globalid
307 )
308{
309 /// The main problem here is that we have to know how many same
310 /// elements (but different atoms!) we are required to find. Hence,
311 /// we first have to count same elements, then get different targets
312 /// for each and then associated them in correct order back again.
313
314 // 0. if no elements given, we return empty arguments
315 if (elements.empty())
316 return FunctionModel::arguments_t();
317
318 // 1. we have to place each charge into a map as unique chargeiter, i.e. map
319 elementtargets_t elementtargets =
320 Extractors::_detail::convertChargesToTargetMap(
321 charges,
322 elements);
323
324 // 2. now we have to combine elementcounts out of elementtargets per desired element
325 // in a combinatorial fashion
326 targets_per_combination_t combinations =
327 Extractors::_detail::CombineChargesAndTargets(
328 elements,
329 elementtargets);
330
331 // 3. finally, convert chargeiters into argument list
332 FunctionModel::arguments_t args =
333 Extractors::_detail::convertTargetsToArguments(
334 positions,
335 charges,
336 combinations,
337 globalid);
338
339 return args;
340}
341
342Extractors::targets_per_combination_t
343Extractors::_detail::CombineChargesAndTargets(
344 const Fragment::charges_t& elements,
345 const elementtargets_t& elementtargets
346 )
347{
348 // recursively create all correct combinations of targets
349 targets_per_combination_t combinations;
350 chargeiters_t currenttargets;
351 boost::function<void (const chargeiters_t &currenttargets)> addFunction =
352 boost::bind(&targets_per_combination_t::push_back,
353 boost::ref(combinations),
354 _1);
355 pickLastElementAsTarget(elements, elementtargets, currenttargets, addFunction);
356
357 return combinations;
358}
359
360const Fragment::position_t& getPositionToChargeIter(
361 const Fragment::positions_t& positions,
362 const Fragment::charges_t& charges,
363 const Extractors::chargeiter_t &iter
364 )
365{
366 Fragment::positions_t::const_iterator positer = positions.begin();
367 std::advance(positer, std::distance(charges.begin(), iter));
368 const Fragment::position_t &position = *positer;
369 return position;
370}
371
372
373FunctionModel::arguments_t
374Extractors::_detail::convertTargetsToArguments(
375 const Fragment::positions_t& positions,
376 const Fragment::charges_t& charges,
377 const targets_per_combination_t combinations,
378 const size_t globalid
379 )
380{
381 FunctionModel::arguments_t args;
382 // create arguments from each combination. We cannot use
383 // gatherallSymmetricDistanceArguments() because it would not create the
384 // correct indices.
385 for (targets_per_combination_t::const_iterator iter = combinations.begin();
386 iter != combinations.end();
387 ++iter) {
388 for(chargeiters_t::const_iterator firstiter = iter->begin();
389 firstiter != iter->end();
390 ++firstiter) {
391 const Fragment::position_t &firstpos =
392 getPositionToChargeIter(positions, charges, *firstiter);
393 const Vector firsttemp(firstpos[0],firstpos[1],firstpos[2]);
394 for(chargeiters_t::const_iterator seconditer = firstiter;
395 seconditer != iter->end();
396 ++seconditer) {
397 if (firstiter == seconditer)
398 continue;
399 const Fragment::position_t &secondpos =
400 getPositionToChargeIter(positions, charges, *seconditer);
401 const Vector secondtemp(secondpos[0],secondpos[1],secondpos[2]);
402 argument_t arg;
403 arg.distance = firsttemp.distance(secondtemp);
404 arg.indices.first = std::distance(charges.begin(), *firstiter);
405 arg.indices.second = std::distance(charges.begin(), *seconditer);
406 arg.types.first = **firstiter;
407 arg.types.second = **seconditer;
408 args.push_back( arg );
409 }
410 }
411 }
412
413 return args;
414}
415
416void
417Extractors::_detail::pickLastElementAsTarget(
418 Fragment::charges_t elements,
419 elementtargets_t elementtargets,
420 chargeiters_t &currenttargets,
421 boost::function<void (const chargeiters_t &currenttargets)> &addFunction
422 )
423{
424 // get last element from charges
425 ASSERT( !elements.empty(),
426 "Extractors::_detail::pickLastElementAsTarget() - no elements given to pick targets for.");
427 const Fragment::charge_t charge = elements.back();
428 elements.pop_back();
429 elementtargets_t::iterator iter = elementtargets.find(charge);
430 if (iter == elementtargets.end())
431 return;
432 bool NotEmpty = !iter->second.empty();
433 while (NotEmpty) {
434 // get last target from the vector of chargeiters
435 chargeiter_t target = iter->second.back();
436 iter->second.pop_back();
437 // remove this key if empty
438 if (iter->second.empty()) {
439 elementtargets.erase(iter);
440 NotEmpty = false;
441 }
442 currenttargets.push_back(target);
443 if (elements.empty()) {
444 // call add function
445 {
446 std::stringstream targetstream;
447 BOOST_FOREACH( chargeiter_t target, currenttargets ) {
448 targetstream << " " << *target;
449 }
450 LOG(3, "DEBUG: Adding set" << targetstream.str() << ".");
451 }
452 addFunction(currenttargets);
453 } else {
454 // if not, call us recursively
455 pickLastElementAsTarget(elements, elementtargets, currenttargets, addFunction);
456 }
457 // pop last in currenset again
458 currenttargets.pop_back();
459 }
460}
461
462Extractors::chargeiters_t
463Extractors::_detail::gatherTargetsFromFragment(
464 const Fragment::charges_t& charges,
465 const Fragment::charges_t elements
466 )
467{
468 /// The main problem here is that we have to know how many same
469 /// elements (but different atoms!) we are required to find. Hence,
470 /// we first have to count same elements, then get different targets
471 /// for each and then associated them in correct order back again.
472
473 // 1. we have to make elements unique with counts, hence convert to map
474 elementcounts_t elementcounts =
475 Extractors::_detail::getElementCounts(elements);
476
477 // 2. then for each element we need as many targets (chargeiters) as counts
478 elementtargets_t elementtargets =
479 Extractors::_detail::convertElementcountsToTargets(charges, elementcounts);
480
481 // 3. we go again through elements and use one found target for each count
482 // in that order
483 chargeiters_t targets =
484 Extractors::_detail::realignElementtargets(elementtargets, elements, elementcounts);
485
486#ifndef NDEBUG
487 // check all for debugging
488 for (chargeiters_t::const_iterator chargeiter = targets.begin();
489 chargeiter != targets.end();
490 ++chargeiter)
491 ASSERT( *chargeiter != charges.end(),
492 "Extractors::gatherTargetsFromFragment() - we have not found enough targets?!");
493#endif
494
495 return targets;
496}
497
498Fragment::positions_t
499Extractors::gatherPositionsFromFragment(
500 const Fragment::positions_t positions,
501 const Fragment::charges_t charges,
502 const Fragment::charges_t& elements
503 )
504{
505 // 1.-3. gather correct charge positions
506 chargeiters_t targets =
507 Extractors::_detail::gatherTargetsFromFragment(charges, elements);
508 // 4. convert position_t to Vector
509 return Extractors::_detail::gatherPositionsFromTargets(
510 positions,
511 charges,
512 targets);
513}
514
515FunctionModel::arguments_t
516Extractors::gatherDistancesFromFragment(
517 const Fragment::positions_t positions,
518 const Fragment::charges_t charges,
519 const Fragment::charges_t& elements,
520 const size_t globalid
521 )
522{
523 // 1.-3. gather correct charge positions
524 chargeiters_t targets =
525 Extractors::_detail::gatherTargetsFromFragment(charges, elements);
526 // 4. convert position_t to Vector
527 return Extractors::_detail::gatherDistancesFromTargets(
528 positions,
529 charges,
530 targets,
531 globalid);
532}
533
534FunctionModel::list_of_arguments_t Extractors::reorderArgumentsByIncreasingDistance(
535 const FunctionModel::list_of_arguments_t &listargs
536 )
537{
538 FunctionModel::list_of_arguments_t returnargs;
539 for (FunctionModel::list_of_arguments_t::const_iterator iter = listargs.begin();
540 iter != listargs.end(); ++iter) {
541 const FunctionModel::arguments_t &args = *iter;
542 FunctionModel::arguments_t sortedargs(args);
543 std::sort(sortedargs.begin(), sortedargs.end(), argument_t::DistanceComparator);
544 returnargs.push_back(sortedargs);
545 }
546 return returnargs;
547}
548
549
550struct ParticleTypesComparator {
551 bool operator()(const argument_t::types_t &a, const argument_t::types_t &b)
552 {
553 if (a.first < a.second) {
554 if (b.first < b.second) {
555 if (a.first < b.first)
556 return true;
557 else if (a.first > b.first)
558 return false;
559 else
560 return (a.second < b.second);
561 } else {
562 if (a.first < b.second)
563 return true;
564 else if (a.first > b.second)
565 return false;
566 else
567 return (a.second < b.first);
568 }
569 } else {
570 if (b.first < b.second) {
571 if (a.second < b.first)
572 return true;
573 else if (a.second > b.first)
574 return false;
575 else
576 return (a.first < b.second);
577 } else {
578 if (a.second < b.second)
579 return true;
580 else if (a.second > b.second)
581 return false;
582 else
583 return (a.first < b.first);
584 }
585 }
586 }
587};
588
589std::ostream& operator<<(std::ostream &out, const argument_t::types_t &a)
590{
591 out << "[" << a.first << "," << a.second << "]";
592 return out;
593}
594
595FunctionModel::list_of_arguments_t Extractors::reorderArgumentsByParticleTypes(
596 const FunctionModel::list_of_arguments_t &listargs,
597 const ParticleTypes_t &_types
598 )
599{
600 FunctionModel::list_of_arguments_t returnargs;
601 for (FunctionModel::list_of_arguments_t::const_iterator iter = listargs.begin();
602 iter != listargs.end(); ++iter) {
603 const FunctionModel::arguments_t &args = *iter;
604 /// We place all arguments into multimap according to particle type pair.
605 // here, we need a special comparator such that types in key pair are always
606 // properly ordered.
607 typedef std::multimap<
608 argument_t::types_t,
609 argument_t,
610 ParticleTypesComparator> TypePair_Argument_Map_t;
611 TypePair_Argument_Map_t argument_map;
612 for(FunctionModel::arguments_t::const_iterator iter = args.begin();
613 iter != args.end(); ++iter) {
614 argument_map.insert( std::make_pair(iter->types, *iter) );
615 }
616 LOG(4, "DEBUG: particle_type map is " << argument_map << ".");
617
618 /// Then, we create the desired unique keys
619 typedef std::vector<argument_t::types_t> UniqueTypes_t;
620 UniqueTypes_t UniqueTypes;
621 for (ParticleTypes_t::const_iterator firstiter = _types.begin();
622 firstiter != _types.end();
623 ++firstiter) {
624 for (ParticleTypes_t::const_iterator seconditer = firstiter;
625 seconditer != _types.end();
626 ++seconditer) {
627 if (seconditer == firstiter)
628 continue;
629 UniqueTypes.push_back( std::make_pair(*firstiter, *seconditer) );
630 }
631 }
632 LOG(4, "DEBUG: Created unique types as keys " << UniqueTypes << ".");
633
634 /// Finally, we use the unique key list to pick corresponding arguments from the map
635 FunctionModel::arguments_t sortedargs;
636 sortedargs.reserve(args.size());
637 while (!argument_map.empty()) {
638 // note that particle_types_t may be flipped, i.e. 1,8 is equal to 8,1, but we
639 // must maintain the correct order in indices in accordance with the order
640 // in _types, i.e. 1,8,1 must match with e.g. ids 1,0,2 where 1 has type 1,
641 // 0 has type 8, and 2 has type 2.
642 // In other words: We do not want to flip/modify arguments such that they match
643 // with the specific type pair we seek but then this comes at the price that we
644 // have flip indices when the types in a pair are flipped.
645
646 typedef std::vector<size_t> indices_t;
647 //!> here, we gather the indices as we discover them
648 indices_t indices;
649 indices.resize(_types.size(), (size_t)-1);
650
651 // these are two iterators that create index pairs in the same way as we have
652 // created type pairs. If a -1 is still present in indices, then the index is
653 // still arbitrary but is then set by the next found index
654 indices_t::iterator firstindex = indices.begin();
655 indices_t::iterator secondindex = firstindex+1;
656
657 //!> here, we gather the current bunch of arguments as we find them
658 FunctionModel::arguments_t argumentbunch;
659 argumentbunch.reserve(UniqueTypes.size());
660
661 for (UniqueTypes_t::const_iterator typeiter = UniqueTypes.begin();
662 typeiter != UniqueTypes.end(); ++typeiter) {
663 // have all arguments to same type pair as list within the found range
664 std::pair<
665 TypePair_Argument_Map_t::iterator,
666 TypePair_Argument_Map_t::iterator> range_t =
667 argument_map.equal_range(*typeiter);
668 LOG(4, "DEBUG: Set of arguments to current key [" << typeiter->first << ","
669 << typeiter->second << "] is " << std::list<argument_t>(
670 MapValueIterator<TypePair_Argument_Map_t::iterator>(range_t.first),
671 MapValueIterator<TypePair_Argument_Map_t::iterator>(range_t.second)
672 ) << ".");
673 // the first key is always easy and is pivot which the rest has to be associated to
674 if (typeiter == UniqueTypes.begin()) {
675 const argument_t & arg = range_t.first->second;
676 if ((typeiter->first == arg.types.first) && (typeiter->second == arg.types.second)) {
677 // store in correct order
678 *firstindex = arg.indices.first;
679 *secondindex = arg.indices.second;
680 } else {
681 // store in flipped order
682 *firstindex = arg.indices.second;
683 *secondindex = arg.indices.first;
684 }
685 argumentbunch.push_back(arg);
686 argument_map.erase(range_t.first);
687 LOG(4, "DEBUG: Gathered first argument " << arg << ".");
688 } else {
689 // go through the range and pick the first argument matching the index constraints
690 for (TypePair_Argument_Map_t::iterator argiter = range_t.first;
691 argiter != range_t.second; ++argiter) {
692 // seconditer may be -1 still
693 const argument_t &arg = argiter->second;
694 if (arg.indices.first == *firstindex) {
695 if ((arg.indices.second == *secondindex) || (*secondindex == (size_t)-1)) {
696 if (*secondindex == (size_t)-1)
697 *secondindex = arg.indices.second;
698 argumentbunch.push_back(arg);
699 argument_map.erase(argiter);
700 LOG(4, "DEBUG: Gathered another argument " << arg << ".");
701 break;
702 }
703 } else if ((arg.indices.first == *secondindex) || (*secondindex == (size_t)-1)) {
704 if (arg.indices.second == *firstindex) {
705 if (*secondindex == (size_t)-1)
706 *secondindex = arg.indices.first;
707 argumentbunch.push_back(arg);
708 argument_map.erase(argiter);
709 LOG(4, "DEBUG: Gathered another (flipped) argument " << arg << ".");
710 break;
711 }
712 }
713 }
714 }
715 // move along in indices and check bounds
716 ++secondindex;
717 if (secondindex == indices.end()) {
718 ++firstindex;
719 if (firstindex != indices.end()-1)
720 secondindex = firstindex+1;
721 }
722 }
723 ASSERT( (firstindex == indices.end()-1) && (secondindex == indices.end()),
724 "Extractors::reorderArgumentsByParticleTypes() - we have not gathered enough arguments.");
725 ASSERT( argumentbunch.size() == UniqueTypes.size(),
726 "Extractors::reorderArgumentsByParticleTypes() - we have not gathered enough arguments.");
727 // place bunch of arguments in return args
728 LOG(3, "DEBUG: Given types " << _types << " and found indices " << indices << ".");
729 LOG(3, "DEBUG: Final bunch of arguments is " << argumentbunch << ".");
730 sortedargs.insert(sortedargs.end(), argumentbunch.begin(), argumentbunch.end());
731 }
732 returnargs.push_back(sortedargs);
733 }
734
735 return returnargs;
736}
737
738FunctionModel::list_of_arguments_t Extractors::filterArgumentsByParticleTypes(
739 const FunctionModel::arguments_t &args,
740 const ParticleTypes_t &_types
741 )
742{
743 typedef std::list< argument_t > ListArguments_t;
744 ListArguments_t availableList(args.begin(), args.end());
745 LOG(2, "DEBUG: Initial list of args is " << args << ".");
746
747
748 // TODO: fill a lookup map such that we don't have O(M^3) scaling, if M is number
749 // of types (and we always must have M(M-1)/2 args) but O(M^2 log(M)). However, as
750 // M is very small (<=3), this is not necessary fruitful now.
751// typedef ParticleTypes_t firsttype;
752// typedef ParticleTypes_t secondtype;
753// typedef std::map< firsttype, std::map< secondtype, boost::ref(args) > > ArgsLookup_t;
754// ArgsLookup_t ArgsLookup;
755
756 // basically, we have two choose any two pairs out of types but only those
757 // where the first is less than the latter. Hence, we start the second
758 // iterator at the current position of the first one and skip the equal case.
759 FunctionModel::arguments_t allargs;
760 allargs.reserve(args.size());
761 for (ParticleTypes_t::const_iterator firstiter = _types.begin();
762 firstiter != _types.end();
763 ++firstiter) {
764 for (ParticleTypes_t::const_iterator seconditer = firstiter;
765 seconditer != _types.end();
766 ++seconditer) {
767 if (seconditer == firstiter)
768 continue;
769 LOG(3, "DEBUG: Looking for (" << *firstiter << "," << *seconditer << ") in all args.");
770
771 // search the right one in _args (we might allow switching places of
772 // firstiter and seconditer, as distance is symmetric).
773 ListArguments_t::iterator iter = availableList.begin();
774 while (iter != availableList.end()) {
775 LOG(4, "DEBUG: Current args is " << *iter << ".");
776 if ((iter->types.first == *firstiter)
777 && (iter->types.second == *seconditer)) {
778 allargs.push_back( *iter );
779 iter = availableList.erase(iter);
780 LOG(4, "DEBUG: Accepted argument.");
781 } else if ((iter->types.first == *seconditer)
782 && (iter->types.second == *firstiter)) {
783 allargs.push_back( *iter );
784 iter = availableList.erase(iter);
785 LOG(4, "DEBUG: Accepted (flipped) argument.");
786 } else {
787 ++iter;
788 LOG(4, "DEBUG: Rejected argument.");
789 }
790 }
791 }
792 }
793 LOG(2, "DEBUG: Final list of args is " << allargs << ".");
794
795 // first, we bring together tuples of distances that belong together
796 FunctionModel::list_of_arguments_t singlelist_allargs;
797 singlelist_allargs.push_back(allargs);
798 FunctionModel::list_of_arguments_t sortedargs =
799 reorderArgumentsByParticleTypes(singlelist_allargs, _types);
800 ASSERT( sortedargs.size() == (size_t)1,
801 "Extractors::filterArgumentsByParticleTypes() - reordering did not generate a single list.");
802 // then we split up the tuples of arguments and place each into single list
803 FunctionModel::list_of_arguments_t returnargs;
804 FunctionModel::arguments_t::const_iterator argiter = sortedargs.begin()->begin();
805 const size_t num_types = _types.size();
806 const size_t args_per_tuple = num_types * (num_types-1) / 2;
807 while (argiter != sortedargs.begin()->end()) {
808 FunctionModel::arguments_t currenttuple(args_per_tuple);
809 const FunctionModel::arguments_t::const_iterator startiter = argiter;
810 std::advance(argiter, args_per_tuple);
811#ifndef NDEBUG
812 FunctionModel::arguments_t::const_iterator endoutiter =
813#endif
814 std::copy(startiter, argiter, currenttuple.begin());
815 ASSERT( endoutiter == currenttuple.end(),
816 "Extractors::filterArgumentsByParticleTypes() - currenttuple not initialized to right size.");
817 returnargs.push_back(currenttuple);
818 }
819
820 LOG(2, "DEBUG: We have generated " << returnargs.size() << " tuples of distances.");
821
822 return returnargs;
823}
824
825
826FunctionModel::arguments_t Extractors::combineArguments(
827 const FunctionModel::arguments_t &firstargs,
828 const FunctionModel::arguments_t &secondargs)
829{
830 FunctionModel::arguments_t args = concatenateArguments(firstargs, secondargs);
831 std::sort(args.begin(), args.end(),
832 boost::bind(&argument_t::operator<, _1, _2));
833 FunctionModel::arguments_t::iterator iter =
834 std::unique(args.begin(), args.end(),
835 boost::bind(&argument_t::operator==, _1, _2));
836 args.erase(iter, args.end());
837 return args;
838}
839
840FunctionModel::arguments_t Extractors::concatenateArguments(
841 const FunctionModel::arguments_t &firstargs,
842 const FunctionModel::arguments_t &secondargs)
843{
844 FunctionModel::arguments_t args(firstargs);
845 args.insert(args.end(), secondargs.begin(), secondargs.end());
846 return args;
847}
848
849FunctionModel::list_of_arguments_t Extractors::concatenateListOfArguments(
850 const FunctionModel::list_of_arguments_t &firstlistargs,
851 const FunctionModel::list_of_arguments_t &secondlistargs)
852{
853 FunctionModel::list_of_arguments_t listargs(firstlistargs);
854 listargs.insert(listargs.end(), secondlistargs.begin(), secondlistargs.end());
855 return listargs;
856}
Note: See TracBrowser for help on using the repository browser.