source: src/FunctionApproximation/Extractors.cpp@ af2c7ec

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 af2c7ec was 31a2be, checked in by Frederik Heber <heber@…>, 12 years ago

FIX: Extractors::filterArgumentsByParticleTypes() did wrongly break on first found argument.

  • also added lots of staggered debugging output.
  • Property mode set to 100644
File size: 28.7 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::arguments_t Extractors::reorderArgumentsByIncreasingDistance(
535 const FunctionModel::arguments_t &args
536 )
537{
538 FunctionModel::arguments_t returnargs(args);
539 std::sort(returnargs.begin(), returnargs.end(), argument_t::DistanceComparator);
540 return returnargs;
541}
542
543
544struct ParticleTypesComparator {
545 bool operator()(const argument_t::types_t &a, const argument_t::types_t &b)
546 {
547 if (a.first < a.second) {
548 if (b.first < b.second) {
549 if (a.first < b.first)
550 return true;
551 else if (a.first > b.first)
552 return false;
553 else
554 return (a.second < b.second);
555 } else {
556 if (a.first < b.second)
557 return true;
558 else if (a.first > b.second)
559 return false;
560 else
561 return (a.second < b.first);
562 }
563 } else {
564 if (b.first < b.second) {
565 if (a.second < b.first)
566 return true;
567 else if (a.second > b.first)
568 return false;
569 else
570 return (a.first < b.second);
571 } else {
572 if (a.second < b.second)
573 return true;
574 else if (a.second > b.second)
575 return false;
576 else
577 return (a.first < b.first);
578 }
579 }
580 }
581};
582
583std::ostream& operator<<(std::ostream &out, const argument_t::types_t &a)
584{
585 out << "[" << a.first << "," << a.second << "]";
586 return out;
587}
588
589FunctionModel::arguments_t Extractors::reorderArgumentsByParticleTypes(
590 const FunctionModel::arguments_t &args,
591 const ParticleTypes_t &_types
592 )
593{
594 /// We place all arguments into multimap according to particle type pair.
595 // here, we need a special comparator such that types in key pair are always
596 // properly ordered.
597 typedef std::multimap<
598 argument_t::types_t,
599 argument_t,
600 ParticleTypesComparator> TypePair_Argument_Map_t;
601 TypePair_Argument_Map_t argument_map;
602 for(FunctionModel::arguments_t::const_iterator iter = args.begin();
603 iter != args.end(); ++iter) {
604 argument_map.insert( std::make_pair(iter->types, *iter) );
605 }
606 LOG(4, "DEBUG: particle_type map is " << argument_map << ".");
607
608 /// Then, we create the desired unique keys
609 typedef std::vector<argument_t::types_t> UniqueTypes_t;
610 UniqueTypes_t UniqueTypes;
611 for (ParticleTypes_t::const_iterator firstiter = _types.begin();
612 firstiter != _types.end();
613 ++firstiter) {
614 for (ParticleTypes_t::const_iterator seconditer = firstiter;
615 seconditer != _types.end();
616 ++seconditer) {
617 if (seconditer == firstiter)
618 continue;
619 UniqueTypes.push_back( std::make_pair(*firstiter, *seconditer) );
620 }
621 }
622 LOG(4, "DEBUG: Created unique types as keys " << UniqueTypes << ".");
623
624 /// Finally, we use the unique key list to pick corresponding arguments from the map
625 FunctionModel::arguments_t returnargs;
626 returnargs.reserve(args.size());
627 while (!argument_map.empty()) {
628 // note that particle_types_t may be flipped, i.e. 1,8 is equal to 8,1, but we
629 // must maintain the correct order in indices in accordance with the order
630 // in _types, i.e. 1,8,1 must match with e.g. ids 1,0,2 where 1 has type 1,
631 // 0 has type 8, and 2 has type 2.
632 // In other words: We do not want to flip/modify arguments such that they match
633 // with the specific type pair we seek but then this comes at the price that we
634 // have flip indices when the types in a pair are flipped.
635
636 typedef std::vector<size_t> indices_t;
637 //!> here, we gather the indices as we discover them
638 indices_t indices;
639 indices.resize(_types.size(), (size_t)-1);
640
641 // these are two iterators that create index pairs in the same way as we have
642 // created type pairs. If a -1 is still present in indices, then the index is
643 // still arbitrary but is then set by the next found index
644 indices_t::iterator firstindex = indices.begin();
645 indices_t::iterator secondindex = firstindex+1;
646
647 //!> here, we gather the current bunch of arguments as we find them
648 FunctionModel::arguments_t argumentbunch;
649 argumentbunch.reserve(UniqueTypes.size());
650
651 for (UniqueTypes_t::const_iterator typeiter = UniqueTypes.begin();
652 typeiter != UniqueTypes.end(); ++typeiter) {
653 // have all arguments to same type pair as list within the found range
654 std::pair<
655 TypePair_Argument_Map_t::iterator,
656 TypePair_Argument_Map_t::iterator> range_t =
657 argument_map.equal_range(*typeiter);
658 LOG(4, "DEBUG: Set of arguments to current key [" << typeiter->first << ","
659 << typeiter->second << "] is " << std::list<argument_t>(
660 MapValueIterator<TypePair_Argument_Map_t::iterator>(range_t.first),
661 MapValueIterator<TypePair_Argument_Map_t::iterator>(range_t.second)
662 ) << ".");
663 // the first key is always easy and is pivot which the rest has to be associated to
664 if (typeiter == UniqueTypes.begin()) {
665 const argument_t & arg = range_t.first->second;
666 if ((typeiter->first == arg.types.first) && (typeiter->second == arg.types.second)) {
667 // store in correct order
668 *firstindex = arg.indices.first;
669 *secondindex = arg.indices.second;
670 } else {
671 // store in flipped order
672 *firstindex = arg.indices.second;
673 *secondindex = arg.indices.first;
674 }
675 argumentbunch.push_back(arg);
676 argument_map.erase(range_t.first);
677 LOG(4, "DEBUG: Gathered first argument " << arg << ".");
678 } else {
679 // go through the range and pick the first argument matching the index constraints
680 for (TypePair_Argument_Map_t::iterator argiter = range_t.first;
681 argiter != range_t.second; ++argiter) {
682 // seconditer may be -1 still
683 const argument_t &arg = argiter->second;
684 if (arg.indices.first == *firstindex) {
685 if ((arg.indices.second == *secondindex) || (*secondindex == (size_t)-1)) {
686 if (*secondindex == -1)
687 *secondindex = arg.indices.second;
688 argumentbunch.push_back(arg);
689 argument_map.erase(argiter);
690 LOG(4, "DEBUG: Gathered another argument " << arg << ".");
691 break;
692 }
693 } else if ((arg.indices.first == *secondindex) || (*secondindex == (size_t)-1)) {
694 if (arg.indices.second == *firstindex) {
695 if (*secondindex == (size_t)-1)
696 *secondindex = arg.indices.first;
697 argumentbunch.push_back(arg);
698 argument_map.erase(argiter);
699 LOG(4, "DEBUG: Gathered another (flipped) argument " << arg << ".");
700 break;
701 }
702 }
703 }
704 }
705 // move along in indices and check bounds
706 ++secondindex;
707 if (secondindex == indices.end()) {
708 ++firstindex;
709 if (firstindex != indices.end()-1)
710 secondindex = firstindex+1;
711 }
712 }
713 ASSERT( (firstindex == indices.end()-1) && (secondindex == indices.end()),
714 "Extractors::reorderArgumentsByParticleTypes() - we have not gathered enough arguments.");
715 ASSERT( argumentbunch.size() == UniqueTypes.size(),
716 "Extractors::reorderArgumentsByParticleTypes() - we have not gathered enough arguments.");
717 // place bunch of arguments in return args
718 LOG(3, "DEBUG: Given types " << _types << " and found indices " << indices << ".");
719 LOG(3, "DEBUG: Final bunch of arguments is " << argumentbunch << ".");
720 returnargs.insert(returnargs.end(), argumentbunch.begin(), argumentbunch.end());
721 }
722
723 return returnargs;
724}
725
726FunctionModel::arguments_t Extractors::filterArgumentsByParticleTypes(
727 const FunctionModel::arguments_t &args,
728 const ParticleTypes_t &_types
729 )
730{
731 typedef std::list< argument_t > ListArguments_t;
732 ListArguments_t availableList(args.begin(), args.end());
733 LOG(2, "DEBUG: Initial list of args is " << args << ".");
734
735
736 // TODO: fill a lookup map such that we don't have O(M^3) scaling, if M is number
737 // of types (and we always must have M(M-1)/2 args) but O(M^2 log(M)). However, as
738 // M is very small (<=3), this is not necessary fruitful now.
739// typedef ParticleTypes_t firsttype;
740// typedef ParticleTypes_t secondtype;
741// typedef std::map< firsttype, std::map< secondtype, boost::ref(args) > > ArgsLookup_t;
742// ArgsLookup_t ArgsLookup;
743
744 // basically, we have two choose any two pairs out of types but only those
745 // where the first is less than the latter. Hence, we start the second
746 // iterator at the current position of the first one and skip the equal case.
747 FunctionModel::arguments_t returnargs;
748 returnargs.reserve(args.size());
749 for (ParticleTypes_t::const_iterator firstiter = _types.begin();
750 firstiter != _types.end();
751 ++firstiter) {
752 for (ParticleTypes_t::const_iterator seconditer = firstiter;
753 seconditer != _types.end();
754 ++seconditer) {
755 if (seconditer == firstiter)
756 continue;
757
758 // search the right one in _args (we might allow switching places of
759 // firstiter and seconditer, as distance is symmetric).
760 ListArguments_t::iterator iter = availableList.begin();
761 while (iter != availableList.end()) {
762 LOG(3, "DEBUG: Current args is " << *iter << ".");
763 if ((iter->types.first == *firstiter)
764 && (iter->types.second == *seconditer)) {
765 returnargs.push_back( *iter );
766 iter = availableList.erase(iter);
767 LOG(4, "DEBUG: Accepted argument.");
768 } else if ((iter->types.first == *seconditer)
769 && (iter->types.second == *firstiter)) {
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 }
779 }
780 LOG(2, "DEBUG: Final list of args is " << returnargs << ".");
781
782 return returnargs;
783}
784
785
786FunctionModel::arguments_t Extractors::combineArguments(
787 const FunctionModel::arguments_t &firstargs,
788 const FunctionModel::arguments_t &secondargs)
789{
790 FunctionModel::arguments_t args = concatenateArguments(firstargs, secondargs);
791 std::sort(args.begin(), args.end(),
792 boost::bind(&argument_t::operator<, _1, _2));
793 FunctionModel::arguments_t::iterator iter =
794 std::unique(args.begin(), args.end(),
795 boost::bind(&argument_t::operator==, _1, _2));
796 args.erase(iter, args.end());
797 return args;
798}
799
800FunctionModel::arguments_t Extractors::concatenateArguments(
801 const FunctionModel::arguments_t &firstargs,
802 const FunctionModel::arguments_t &secondargs)
803{
804 FunctionModel::arguments_t args(firstargs);
805 args.insert(args.end(), secondargs.begin(), secondargs.end());
806 return args;
807}
808
Note: See TracBrowser for help on using the repository browser.