source: src/FunctionApproximation/Extractors.cpp@ 51e0e3

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 51e0e3 was 51e0e3, checked in by Frederik Heber <heber@…>, 11 years ago

Added two filter functions to Extractors.

  • renamed reorderArgumentsByParticleTypes()->filterArgumentsByParticleTypes().
  • added reorderArgumentsByParticleTypes() that expects arguments matching to given particle types and which reorders into matching bunches with associated indices.
  • added suitable combination of the two filter as each potential's specific filter.
  • had to add specific comparator for Particle_Types_t to allow flipped types in argument_map.
  • reorderArgumentsByParticleTypes() prints with enhanced toString.
  • FIX: Histogram did not use the pair-wise operator<<(). (this occured because of new operator<<(..,pair) from toString.hpp).
  • we enforce CodePatterns 1.2.7 now.
  • Property mode set to 100644
File size: 29.0 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 result.push_back(arg);
126 }
127 }
128
129 return result;
130}
131
132Fragment::positions_t Extractors::_detail::gatherPositionsFromTargets(
133 const Fragment::positions_t& positions,
134 const Fragment::charges_t& charges,
135 const chargeiters_t &targets
136 )
137{
138 Fragment::positions_t filtered_positions;
139 for (chargeiters_t::const_iterator firstpairiter = targets.begin();
140 firstpairiter != targets.end(); ++firstpairiter) {
141 Fragment::positions_t::const_iterator positer = positions.begin();
142 const size_t steps = std::distance(charges.begin(), *firstpairiter);
143 std::advance(positer, steps);
144 filtered_positions.push_back(*positer);
145 }
146 return filtered_positions;
147}
148
149FunctionModel::arguments_t Extractors::_detail::gatherDistancesFromTargets(
150 const Fragment::positions_t& positions,
151 const Fragment::charges_t& charges,
152 const chargeiters_t &targets,
153 const size_t globalid
154 )
155{
156 Fragment::positions_t filtered_positions;
157 Fragment::charges_t filtered_charges;
158 for (chargeiters_t::const_iterator firstpairiter = targets.begin();
159 firstpairiter != targets.end(); ++firstpairiter) {
160 Fragment::positions_t::const_iterator positer = positions.begin();
161 const size_t steps = std::distance(charges.begin(), *firstpairiter);
162 std::advance(positer, steps);
163 filtered_positions.push_back(*positer);
164 filtered_charges.push_back(**firstpairiter);
165 }
166 return Extractors::gatherAllSymmetricDistanceArguments(
167 filtered_positions,
168 filtered_charges,
169 globalid);
170}
171
172Extractors::elementcounts_t
173Extractors::_detail::getElementCounts(
174 const Fragment::charges_t elements
175 )
176{
177 elementcounts_t elementcounts;
178 for (Fragment::charges_t::const_iterator elementiter = elements.begin();
179 elementiter != elements.end(); ++elementiter) {
180 // insert new element
181 std::pair< elementcounts_t::iterator, bool> inserter =
182 elementcounts.insert( std::make_pair( *elementiter, 1) );
183 // if already present, just increase its count
184 if (!inserter.second)
185 ++(inserter.first->second);
186 }
187 return elementcounts;
188}
189
190Extractors::elementtargets_t
191Extractors::_detail::convertElementcountsToTargets(
192 const Fragment::charges_t &charges,
193 const elementcounts_t &elementcounts
194 )
195{
196 elementtargets_t elementtargets;
197 for (elementcounts_t::const_iterator countiter = elementcounts.begin();
198 countiter != elementcounts.end();
199 ++countiter) {
200 chargeiter_t chargeiter = charges.begin();
201 const element_t &element = countiter->first;
202 const count_t &count = countiter->second;
203 for (count_t i = 0; i < count; ++i) {
204 chargeiter_t tempiter = std::find(chargeiter, charges.end(), element);
205 if (tempiter != charges.end()) {
206 // try to insert new list
207 std::pair< elementtargets_t::iterator, bool> inserter =
208 elementtargets.insert( std::make_pair( countiter->first, chargeiters_t(1, tempiter)) );
209 // if already present, append to it
210 if (!inserter.second) {
211 inserter.first->second.push_back(tempiter);
212 } else { // if created, increase vector's reserve to known size
213 inserter.first->second.reserve(countiter->second);
214 }
215 // search from this element onwards then
216 chargeiter = ++tempiter;
217 } else {
218 ELOG(1, "Could not find desired number " << count << " of element "
219 << element << " in fragment with " << charges << ".");
220 return Extractors::elementtargets_t();
221 }
222 }
223 }
224 return elementtargets;
225}
226
227Extractors::elementtargets_t
228Extractors::_detail::convertChargesToTargetMap(
229 const Fragment::charges_t& charges,
230 Fragment::charges_t elements
231 )
232{
233 // place each charge into a map
234 elementtargets_t completeelementtargets;
235 for (chargeiter_t chargeiter = charges.begin();
236 chargeiter != charges.end();
237 ++chargeiter) {
238 std::pair< elementtargets_t::iterator, bool> inserter =
239 completeelementtargets.insert( std::make_pair( *chargeiter, chargeiters_t(1, chargeiter)) );
240 // if already present, append to it
241 if (!inserter.second) {
242 inserter.first->second.push_back(chargeiter);
243 }
244 }
245 // pick out desired charges only
246 std::sort(elements.begin(), elements.end());
247 Fragment::charges_t::iterator eraseiter =
248 std::unique(elements.begin(), elements.end());
249 elements.erase(eraseiter, elements.end());
250 elementtargets_t elementtargets;
251 for(Fragment::charges_t::const_iterator iter = elements.begin();
252 iter != elements.end();
253 ++iter) {
254 elementtargets_t::const_iterator finditer = completeelementtargets.find(*iter);
255 ASSERT( finditer != completeelementtargets.end(),
256 "Extractors::_detail::convertChargesToTargetMap() - no element "+toString(*iter)+" present?");
257 std::pair< elementtargets_t::iterator, bool> inserter =
258 elementtargets.insert( std::make_pair( finditer->first, finditer->second) );
259 ASSERT( inserter.second,
260 "Extractors::_detail::convertChargesToTargetMap() - key twice?");
261 }
262 return elementtargets;
263}
264
265
266Extractors::chargeiters_t
267Extractors::_detail::realignElementtargets(
268 const elementtargets_t &elementtargets,
269 const Fragment::charges_t elements,
270 const elementcounts_t &elementcounts
271 )
272{
273 chargeiters_t targets;
274 elementcounts_t counts; // how many chargeiters of this element have been used
275 if (!elements.empty()) { // skip if no elements given
276 targets.reserve(elements.size());
277 for (Fragment::charges_t::const_iterator elementiter = elements.begin();
278 elementiter != elements.end(); ++elementiter) {
279 const element_t &element = *elementiter;
280 count_t &count = counts[element]; // if not present, std::map creates instances with default of 0
281#ifndef NDEBUG
282 {
283 elementcounts_t::const_iterator testiter = elementcounts.find(element);
284 ASSERT( (testiter != elementcounts.end()) && (count < testiter->second),
285 "Extractors::_detail::realignElementTargets() - we want to use more chargeiters for element "
286 +toString(element)+" than we counted initially.");
287 }
288#endif
289 elementtargets_t::const_iterator targetiter = elementtargets.find(element);
290 if (targetiter != elementtargets.end()) {
291 const chargeiters_t &chargeiters = targetiter->second;
292 const chargeiter_t &chargeiter = chargeiters[count++];
293 targets.push_back(chargeiter);
294 }
295 }
296 }
297 return targets;
298}
299
300FunctionModel::arguments_t
301Extractors::gatherAllDistancesFromFragment(
302 const Fragment::positions_t& positions,
303 const Fragment::charges_t& charges,
304 const Fragment::charges_t elements,
305 const size_t globalid
306 )
307{
308 /// The main problem here is that we have to know how many same
309 /// elements (but different atoms!) we are required to find. Hence,
310 /// we first have to count same elements, then get different targets
311 /// for each and then associated them in correct order back again.
312
313 // 0. if no elements given, we return empty arguments
314 if (elements.empty())
315 return FunctionModel::arguments_t();
316
317 // 1. we have to place each charge into a map as unique chargeiter, i.e. map
318 elementtargets_t elementtargets =
319 Extractors::_detail::convertChargesToTargetMap(
320 charges,
321 elements);
322
323 // 2. now we have to combine elementcounts out of elementtargets per desired element
324 // in a combinatorial fashion
325 targets_per_combination_t combinations =
326 Extractors::_detail::CombineChargesAndTargets(
327 elements,
328 elementtargets);
329
330 // 3. finally, convert chargeiters into argument list
331 FunctionModel::arguments_t args =
332 Extractors::_detail::convertTargetsToArguments(
333 positions,
334 charges,
335 combinations,
336 globalid);
337
338 return args;
339}
340
341Extractors::targets_per_combination_t
342Extractors::_detail::CombineChargesAndTargets(
343 const Fragment::charges_t& elements,
344 const elementtargets_t& elementtargets
345 )
346{
347 // recursively create all correct combinations of targets
348 targets_per_combination_t combinations;
349 chargeiters_t currenttargets;
350 boost::function<void (const chargeiters_t &currenttargets)> addFunction =
351 boost::bind(&targets_per_combination_t::push_back,
352 boost::ref(combinations),
353 _1);
354 pickLastElementAsTarget(elements, elementtargets, currenttargets, addFunction);
355
356 return combinations;
357}
358
359const Fragment::position_t& getPositionToChargeIter(
360 const Fragment::positions_t& positions,
361 const Fragment::charges_t& charges,
362 const Extractors::chargeiter_t &iter
363 )
364{
365 Fragment::positions_t::const_iterator positer = positions.begin();
366 std::advance(positer, std::distance(charges.begin(), iter));
367 const Fragment::position_t &position = *positer;
368 return position;
369}
370
371
372FunctionModel::arguments_t
373Extractors::_detail::convertTargetsToArguments(
374 const Fragment::positions_t& positions,
375 const Fragment::charges_t& charges,
376 const targets_per_combination_t combinations,
377 const size_t globalid
378 )
379{
380 FunctionModel::arguments_t args;
381 // create arguments from each combination. We cannot use
382 // gatherallSymmetricDistanceArguments() because it would not create the
383 // correct indices.
384 for (targets_per_combination_t::const_iterator iter = combinations.begin();
385 iter != combinations.end();
386 ++iter) {
387 for(chargeiters_t::const_iterator firstiter = iter->begin();
388 firstiter != iter->end();
389 ++firstiter) {
390 const Fragment::position_t &firstpos =
391 getPositionToChargeIter(positions, charges, *firstiter);
392 const Vector firsttemp(firstpos[0],firstpos[1],firstpos[2]);
393 for(chargeiters_t::const_iterator seconditer = firstiter;
394 seconditer != iter->end();
395 ++seconditer) {
396 if (firstiter == seconditer)
397 continue;
398 const Fragment::position_t &secondpos =
399 getPositionToChargeIter(positions, charges, *seconditer);
400 const Vector secondtemp(secondpos[0],secondpos[1],secondpos[2]);
401 argument_t arg;
402 arg.distance = firsttemp.distance(secondtemp);
403 arg.indices.first = std::distance(charges.begin(), *firstiter);
404 arg.indices.second = std::distance(charges.begin(), *seconditer);
405 arg.types.first = **firstiter;
406 arg.types.second = **seconditer;
407 args.push_back( arg );
408 }
409 }
410 }
411
412 return args;
413}
414
415void
416Extractors::_detail::pickLastElementAsTarget(
417 Fragment::charges_t elements,
418 elementtargets_t elementtargets,
419 chargeiters_t &currenttargets,
420 boost::function<void (const chargeiters_t &currenttargets)> &addFunction
421 )
422{
423 // get last element from charges
424 ASSERT( !elements.empty(),
425 "Extractors::_detail::pickLastElementAsTarget() - no elements given to pick targets for.");
426 const Fragment::charge_t charge = elements.back();
427 elements.pop_back();
428 elementtargets_t::iterator iter = elementtargets.find(charge);
429 if (iter == elementtargets.end())
430 return;
431 bool NotEmpty = !iter->second.empty();
432 while (NotEmpty) {
433 // get last target from the vector of chargeiters
434 chargeiter_t target = iter->second.back();
435 iter->second.pop_back();
436 // remove this key if empty
437 if (iter->second.empty()) {
438 elementtargets.erase(iter);
439 NotEmpty = false;
440 }
441 currenttargets.push_back(target);
442 if (elements.empty()) {
443 // call add function
444 {
445 std::stringstream targetstream;
446 BOOST_FOREACH( chargeiter_t target, currenttargets ) {
447 targetstream << " " << *target;
448 }
449 LOG(3, "DEBUG: Adding set" << targetstream.str() << ".");
450 }
451 addFunction(currenttargets);
452 } else {
453 // if not, call us recursively
454 pickLastElementAsTarget(elements, elementtargets, currenttargets, addFunction);
455 }
456 // pop last in currenset again
457 currenttargets.pop_back();
458 }
459}
460
461Extractors::chargeiters_t
462Extractors::_detail::gatherTargetsFromFragment(
463 const Fragment::charges_t& charges,
464 const Fragment::charges_t elements
465 )
466{
467 /// The main problem here is that we have to know how many same
468 /// elements (but different atoms!) we are required to find. Hence,
469 /// we first have to count same elements, then get different targets
470 /// for each and then associated them in correct order back again.
471
472 // 1. we have to make elements unique with counts, hence convert to map
473 elementcounts_t elementcounts =
474 Extractors::_detail::getElementCounts(elements);
475
476 // 2. then for each element we need as many targets (chargeiters) as counts
477 elementtargets_t elementtargets =
478 Extractors::_detail::convertElementcountsToTargets(charges, elementcounts);
479
480 // 3. we go again through elements and use one found target for each count
481 // in that order
482 chargeiters_t targets =
483 Extractors::_detail::realignElementtargets(elementtargets, elements, elementcounts);
484
485#ifndef NDEBUG
486 // check all for debugging
487 for (chargeiters_t::const_iterator chargeiter = targets.begin();
488 chargeiter != targets.end();
489 ++chargeiter)
490 ASSERT( *chargeiter != charges.end(),
491 "Extractors::gatherTargetsFromFragment() - we have not found enough targets?!");
492#endif
493
494 return targets;
495}
496
497Fragment::positions_t
498Extractors::gatherPositionsFromFragment(
499 const Fragment::positions_t positions,
500 const Fragment::charges_t charges,
501 const Fragment::charges_t& elements
502 )
503{
504 // 1.-3. gather correct charge positions
505 chargeiters_t targets =
506 Extractors::_detail::gatherTargetsFromFragment(charges, elements);
507 // 4. convert position_t to Vector
508 return Extractors::_detail::gatherPositionsFromTargets(
509 positions,
510 charges,
511 targets);
512}
513
514FunctionModel::arguments_t
515Extractors::gatherDistancesFromFragment(
516 const Fragment::positions_t positions,
517 const Fragment::charges_t charges,
518 const Fragment::charges_t& elements,
519 const size_t globalid
520 )
521{
522 // 1.-3. gather correct charge positions
523 chargeiters_t targets =
524 Extractors::_detail::gatherTargetsFromFragment(charges, elements);
525 // 4. convert position_t to Vector
526 return Extractors::_detail::gatherDistancesFromTargets(
527 positions,
528 charges,
529 targets,
530 globalid);
531}
532
533FunctionModel::arguments_t Extractors::reorderArgumentsByIncreasingDistance(
534 const FunctionModel::arguments_t &args
535 )
536{
537 FunctionModel::arguments_t returnargs(args);
538 std::sort(returnargs.begin(), returnargs.end(), argument_t::DistanceComparator);
539 return returnargs;
540}
541
542
543struct ParticleTypesComparator {
544 bool operator()(const argument_t::types_t &a, const argument_t::types_t &b)
545 {
546 if (a.first < a.second) {
547 if (b.first < b.second) {
548 if (a.first < b.first)
549 return true;
550 else if (a.first > b.first)
551 return false;
552 else
553 return (a.second < b.second);
554 } else {
555 if (a.first < b.second)
556 return true;
557 else if (a.first > b.second)
558 return false;
559 else
560 return (a.second < b.first);
561 }
562 } else {
563 if (b.first < b.second) {
564 if (a.second < b.first)
565 return true;
566 else if (a.second > b.first)
567 return false;
568 else
569 return (a.first < b.second);
570 } else {
571 if (a.second < b.second)
572 return true;
573 else if (a.second > b.second)
574 return false;
575 else
576 return (a.first < b.first);
577 }
578 }
579 }
580};
581
582std::ostream& operator<<(std::ostream &out, const argument_t::types_t &a)
583{
584 out << "[" << a.first << "," << a.second << "]";
585 return out;
586}
587
588FunctionModel::arguments_t Extractors::reorderArgumentsByParticleTypes(
589 const FunctionModel::arguments_t &args,
590 const ParticleTypes_t &_types
591 )
592{
593 /// We place all arguments into multimap according to particle type pair.
594 // here, we need a special comparator such that types in key pair are always
595 // properly ordered.
596 typedef std::multimap<
597 argument_t::types_t,
598 argument_t,
599 ParticleTypesComparator> TypePair_Argument_Map_t;
600 TypePair_Argument_Map_t argument_map;
601 for(FunctionModel::arguments_t::const_iterator iter = args.begin();
602 iter != args.end(); ++iter) {
603 argument_map.insert( std::make_pair(iter->types, *iter) );
604 }
605 LOG(4, "DEBUG: particle_type map is " << argument_map << ".");
606
607 /// Then, we create the desired unique keys
608 typedef std::vector<argument_t::types_t> UniqueTypes_t;
609 UniqueTypes_t UniqueTypes;
610 for (ParticleTypes_t::const_iterator firstiter = _types.begin();
611 firstiter != _types.end();
612 ++firstiter) {
613 for (ParticleTypes_t::const_iterator seconditer = firstiter;
614 seconditer != _types.end();
615 ++seconditer) {
616 if (seconditer == firstiter)
617 continue;
618 UniqueTypes.push_back( std::make_pair(*firstiter, *seconditer) );
619 }
620 }
621 LOG(4, "DEBUG: Created unique types as keys " << UniqueTypes << ".");
622
623 /// Finally, we use the unique key list to pick corresponding arguments from the map
624 FunctionModel::arguments_t returnargs;
625 returnargs.reserve(args.size());
626 while (!argument_map.empty()) {
627 // note that particle_types_t may be flipped, i.e. 1,8 is equal to 8,1, but we
628 // must maintain the correct order in indices in accordance with the order
629 // in _types, i.e. 1,8,1 must match with e.g. ids 1,0,2 where 1 has type 1,
630 // 0 has type 8, and 2 has type 2.
631 // In other words: We do not want to flip/modify arguments such that they match
632 // with the specific type pair we seek but then this comes at the price that we
633 // have flip indices when the types in a pair are flipped.
634
635 typedef std::vector<size_t> indices_t;
636 //!> here, we gather the indices as we discover them
637 indices_t indices;
638 indices.resize(_types.size(), (size_t)-1);
639
640 // these are two iterators that create index pairs in the same way as we have
641 // created type pairs. If a -1 is still present in indices, then the index is
642 // still arbitrary but is then set by the next found index
643 indices_t::iterator firstindex = indices.begin();
644 indices_t::iterator secondindex = firstindex+1;
645
646 //!> here, we gather the current bunch of arguments as we find them
647 FunctionModel::arguments_t argumentbunch;
648 argumentbunch.reserve(UniqueTypes.size());
649
650 for (UniqueTypes_t::const_iterator typeiter = UniqueTypes.begin();
651 typeiter != UniqueTypes.end(); ++typeiter) {
652 // have all arguments to same type pair as list within the found range
653 std::pair<
654 TypePair_Argument_Map_t::iterator,
655 TypePair_Argument_Map_t::iterator> range_t =
656 argument_map.equal_range(*typeiter);
657 LOG(4, "DEBUG: Set of arguments to current key [" << typeiter->first << ","
658 << typeiter->second << "] is " << std::list<argument_t>(
659 MapValueIterator<TypePair_Argument_Map_t::iterator>(range_t.first),
660 MapValueIterator<TypePair_Argument_Map_t::iterator>(range_t.second)
661 ) << ".");
662 // the first key is always easy and is pivot which the rest has to be associated to
663 if (typeiter == UniqueTypes.begin()) {
664 const argument_t & arg = range_t.first->second;
665 if ((typeiter->first == arg.types.first) && (typeiter->second == arg.types.second)) {
666 // store in correct order
667 *firstindex = arg.indices.first;
668 *secondindex = arg.indices.second;
669 } else {
670 // store in flipped order
671 *firstindex = arg.indices.second;
672 *secondindex = arg.indices.first;
673 }
674 argumentbunch.push_back(arg);
675 argument_map.erase(range_t.first);
676 LOG(4, "DEBUG: Gathered first argument " << arg << ".");
677 } else {
678 // go through the range and pick the first argument matching the index constraints
679 for (TypePair_Argument_Map_t::iterator argiter = range_t.first;
680 argiter != range_t.second; ++argiter) {
681 // seconditer may be -1 still
682 const argument_t &arg = argiter->second;
683 if (arg.indices.first == *firstindex) {
684 if ((arg.indices.second == *secondindex) || (*secondindex == (size_t)-1)) {
685 if (*secondindex == -1)
686 *secondindex = arg.indices.second;
687 argumentbunch.push_back(arg);
688 argument_map.erase(argiter);
689 LOG(4, "DEBUG: Gathered another argument " << arg << ".");
690 break;
691 }
692 } else if ((arg.indices.first == *secondindex) || (*secondindex == (size_t)-1)) {
693 if (arg.indices.second == *firstindex) {
694 if (*secondindex == (size_t)-1)
695 *secondindex = arg.indices.first;
696 argumentbunch.push_back(arg);
697 argument_map.erase(argiter);
698 LOG(4, "DEBUG: Gathered another (flipped) argument " << arg << ".");
699 break;
700 }
701 }
702 }
703 }
704 // move along in indices and check bounds
705 ++secondindex;
706 if (secondindex == indices.end()) {
707 ++firstindex;
708 if (firstindex != indices.end()-1)
709 secondindex = firstindex+1;
710 }
711 }
712 ASSERT( (firstindex == indices.end()-1) && (secondindex == indices.end()),
713 "Extractors::reorderArgumentsByParticleTypes() - we have not gathered enough arguments.");
714 ASSERT( argumentbunch.size() == UniqueTypes.size(),
715 "Extractors::reorderArgumentsByParticleTypes() - we have not gathered enough arguments.");
716 // place bunch of arguments in return args
717 LOG(3, "DEBUG: Given types " << _types << " and found indices " << indices << ".");
718 LOG(3, "DEBUG: Final bunch of arguments is " << argumentbunch << ".");
719 returnargs.insert(returnargs.end(), argumentbunch.begin(), argumentbunch.end());
720 }
721
722 return returnargs;
723}
724
725FunctionModel::arguments_t Extractors::filterArgumentsByParticleTypes(
726 const FunctionModel::arguments_t &args,
727 const ParticleTypes_t &_types
728 )
729{
730 typedef std::list< argument_t > ListArguments_t;
731 ListArguments_t availableList(args.begin(), args.end());
732 FunctionModel::arguments_t returnargs;
733 returnargs.reserve(args.size());
734
735 // TODO: fill a lookup map such that we don't have O(M^3) scaling, if M is number
736 // of types (and we always must have M(M-1)/2 args) but O(M^2 log(M)). However, as
737 // M is very small (<=3), this is not necessary fruitful now.
738// typedef ParticleTypes_t firsttype;
739// typedef ParticleTypes_t secondtype;
740// typedef std::map< firsttype, std::map< secondtype, boost::ref(args) > > ArgsLookup_t;
741// ArgsLookup_t ArgsLookup;
742
743 // basically, we have two choose any two pairs out of types but only those
744 // where the first is less than the latter. Hence, we start the second
745 // iterator at the current position of the first one and skip the equal case.
746 for (ParticleTypes_t::const_iterator firstiter = _types.begin();
747 firstiter != _types.end();
748 ++firstiter) {
749 for (ParticleTypes_t::const_iterator seconditer = firstiter;
750 seconditer != _types.end();
751 ++seconditer) {
752 if (seconditer == firstiter)
753 continue;
754
755 // search the right one in _args (we might allow switching places of
756 // firstiter and seconditer, as distance is symmetric).
757 ListArguments_t::iterator iter = availableList.begin();
758 for (;iter != availableList.end(); ++iter) {
759 LOG(3, "DEBUG: Current args is " << *iter << ".");
760 if ((iter->types.first == *firstiter)
761 && (iter->types.second == *seconditer)) {
762 returnargs.push_back( *iter );
763 break;
764 }
765 else if ((iter->types.first == *seconditer)
766 && (iter->types.second == *firstiter)) {
767// argument_t flippedtypes(*iter);
768// std::swap( flippedtypes.indices.first, flippedtypes.indices.second );
769// std::swap( flippedtypes.types.first, flippedtypes.types.second );
770 returnargs.push_back( *iter );
771 iter = availableList.erase(iter);
772 LOG(4, "DEBUG: Accepted (flipped) argument.");
773 } else {
774 ++iter;
775 LOG(4, "DEBUG: Rejected argument.");
776 }
777 }
778 ASSERT( iter != availableList.end(),
779 "Extractors::reorderArgumentsByParticleTypes() - could not find arguments to "
780 +toString(*firstiter)+","+toString(*seconditer)+".");
781 availableList.erase(iter);
782 }
783 }
784// LOG(2, "DEBUG: Final list of args is " << returnargs << ".");
785
786 return returnargs;
787}
788
789
790FunctionModel::arguments_t Extractors::combineArguments(
791 const FunctionModel::arguments_t &firstargs,
792 const FunctionModel::arguments_t &secondargs)
793{
794 FunctionModel::arguments_t args = concatenateArguments(firstargs, secondargs);
795 std::sort(args.begin(), args.end(),
796 boost::bind(&argument_t::operator<, _1, _2));
797 FunctionModel::arguments_t::iterator iter =
798 std::unique(args.begin(), args.end(),
799 boost::bind(&argument_t::operator==, _1, _2));
800 args.erase(iter, args.end());
801 return args;
802}
803
804FunctionModel::arguments_t Extractors::concatenateArguments(
805 const FunctionModel::arguments_t &firstargs,
806 const FunctionModel::arguments_t &secondargs)
807{
808 FunctionModel::arguments_t args(firstargs);
809 args.insert(args.end(), secondargs.begin(), secondargs.end());
810 return args;
811}
812
Note: See TracBrowser for help on using the repository browser.