Changeset 2124aa for src/FunctionApproximation
- Timestamp:
- Nov 11, 2016, 2:25:30 PM (8 years ago)
- Branches:
- Action_Thermostats, Add_AtomRandomPerturbation, Add_RotateAroundBondAction, Add_SelectAtomByNameAction, Adding_Graph_to_ChangeBondActions, Adding_MD_integration_tests, Adding_StructOpt_integration_tests, Automaking_mpqc_open, AutomationFragmentation_failures, Candidate_v1.6.0, Candidate_v1.6.1, ChangeBugEmailaddress, ChangingTestPorts, ChemicalSpaceEvaluator, 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_ChronosMutex, Fix_StatusMsg, Fix_StepWorldTime_single_argument, Fix_Verbose_Codepatterns, ForceAnnealing_goodresults, ForceAnnealing_oldresults, ForceAnnealing_tocheck, ForceAnnealing_with_BondGraph, ForceAnnealing_with_BondGraph_continued, ForceAnnealing_with_BondGraph_continued_betteresults, ForceAnnealing_with_BondGraph_contraction-expansion, GeometryObjects, Gui_displays_atomic_force_velocity, IndependentFragmentGrids_IntegrationTest, JobMarket_RobustOnKillsSegFaults, JobMarket_StableWorkerPool, JobMarket_unresolvable_hostname_fix, ODR_violation_mpqc_open, PartialCharges_OrthogonalSummation, PythonUI_with_named_parameters, QtGui_reactivate_TimeChanged_changes, Recreated_GuiChecks, RotateToPrincipalAxisSystem_UndoRedo, StoppableMakroAction, Subpackage_CodePatterns, Subpackage_JobMarket, Subpackage_LinearAlgebra, Subpackage_levmar, Subpackage_mpqc_open, Subpackage_vmg, ThirdParty_MPQC_rebuilt_buildsystem, TremoloParser_IncreasedPrecision, TremoloParser_MultipleTimesteps, Ubuntu_1604_changes, stable
- Children:
- c738f1
- Parents:
- 228340
- git-author:
- Frederik Heber <heber@…> (10/04/16 14:05:46)
- git-committer:
- Frederik Heber <heber@…> (11/11/16 14:25:30)
- Location:
- src/FunctionApproximation
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
src/FunctionApproximation/Extractors.cpp
r228340 r2124aa 35 35 #endif 36 36 37 #include <boost/graph/adjacency_list.hpp> 38 #include <boost/graph/breadth_first_search.hpp> 39 #include <boost/graph/subgraph.hpp> 40 37 41 #include "CodePatterns/MemDebug.hpp" 38 42 43 #include <algorithm> 44 #include <iterator> 45 #include <set> 39 46 #include <sstream> 40 47 #include <utility> 41 48 #include <vector> 42 49 #include <boost/assign.hpp> 50 #include <boost/bimap.hpp> 51 #include <boost/bimap/set_of.hpp> 52 #include <boost/bimap/multiset_of.hpp> 43 53 #include <boost/bind.hpp> 44 54 #include <boost/foreach.hpp> … … 66 76 { 67 77 FunctionModel::arguments_t result; 78 79 // place edges in map 80 typedef std::set< std::pair<size_t, size_t> > sorted_edges_t; 81 sorted_edges_t sorted_edges; 82 for (FragmentationEdges::edges_t::const_iterator edgeiter = edges.begin(); 83 edgeiter != edges.end(); ++edgeiter) { 84 std::pair<sorted_edges_t::iterator, bool> inserter = 85 sorted_edges.insert( 86 (edgeiter->first < edgeiter->second) ? 87 std::make_pair(edgeiter->first, edgeiter->second) : 88 std::make_pair(edgeiter->second, edgeiter->first)); 89 ASSERT(inserter.second, 90 "Extractors::gatherAllSymmetricDistanceArguments() - edge " 91 +toString(*inserter.first)+" is already present"); 92 } 68 93 69 94 // go through current configuration and gather all other distances … … 89 114 ); 90 115 arg.globalid = globalid; 91 arg.bonded = false;116 arg.bonded = sorted_edges.find(arg.indices) != sorted_edges.end(); 92 117 LOG(3, "DEBUG: Created argument " << arg << "."); 93 118 result.push_back(arg); … … 161 186 } 162 187 188 typedef size_t level_t; 189 typedef size_t node_t; 190 typedef std::multimap< level_t, node_t > nodes_per_level_t; 191 typedef std::set<node_t> nodes_t; 192 typedef std::set<nodes_t> set_of_nodes_t; 193 typedef boost::property_map < boost::adjacency_list <>, boost::vertex_index_t >::type index_map_t; 194 195 typedef boost::bimap< 196 boost::bimaps::set_of< size_t >, 197 boost::bimaps::multiset_of< Extractors::ParticleType_t > 198 > type_index_lookup_t; 199 200 typedef std::set<node_t> set_type; 201 typedef std::set<set_type> powerset_type; 202 203 typedef boost::adjacency_list < boost::vecS, boost::vecS, boost::undirectedS, 204 boost::no_property, boost::no_property > UndirectedGraph; 205 typedef boost::subgraph< UndirectedGraph > UndirectedSubgraph; 206 207 typedef std::map< node_t, std::pair<Extractors::ParticleType_t, size_t> > node_FragmentNode_map_t; 208 209 typedef std::map< argument_t::indices_t, size_t> argument_placement_map_t; 210 211 typedef std::map<size_t, size_t> argindex_to_nodeindex_t; 212 213 void insertIntoNodeFragmentMap( 214 node_FragmentNode_map_t &_node_FragmentNode_map, 215 const size_t &_index, 216 const Extractors::ParticleType_t &_type) 217 { 218 const node_FragmentNode_map_t::iterator mapiter = _node_FragmentNode_map.find(_index); 219 // check if already present 220 if (mapiter != _node_FragmentNode_map.end()) { 221 // assert same type and increment number of edges 222 ASSERT( mapiter->second.first == _type, 223 "insertIntoNodeFragmentMap() - different types "+toString(mapiter->second.first)+ 224 " and "+toString(_type)+" for node "+toString(_index)); 225 ++(mapiter->second.second); 226 } else { 227 // place new entry with a single present edge 228 _node_FragmentNode_map.insert( std::make_pair(_index, std::make_pair(_type, 1) )); 229 } 230 } 231 232 static node_FragmentNode_map_t fillNodeFragmentMap( 233 FunctionModel::arguments_t &argumentbunch) 234 { 235 node_FragmentNode_map_t node_FragmentNode_map; 236 // place each node index with type and number of edges into map 237 for (FunctionModel::arguments_t::const_iterator argiter = argumentbunch.begin(); 238 argiter != argumentbunch.end(); ++argiter) { 239 const argument_t &arg = *argiter; 240 // only consider the distances that represent a bond edge 241 if (arg.bonded) { 242 insertIntoNodeFragmentMap(node_FragmentNode_map, arg.indices.first, arg.types.first); 243 insertIntoNodeFragmentMap(node_FragmentNode_map, arg.indices.second, arg.types.second); 244 } 245 } 246 247 return node_FragmentNode_map; 248 } 249 250 static argument_placement_map_t fillArgumentsPlacementMap(const size_t num_args) 251 { 252 argument_placement_map_t argument_placement_map; 253 size_t placement = 0; 254 for (size_t i = 0;i<num_args;++i) 255 for (size_t j = i+1;j<num_args;++j) 256 argument_placement_map.insert( std::make_pair( argument_t::indices_t(i,j), placement++) ); 257 return argument_placement_map; 258 } 259 260 static argument_t::indices_t translateIndices( 261 const argindex_to_nodeindex_t &_argindex_to_nodeindex, 262 const argument_t::indices_t &_indices 263 ) 264 { 265 const argindex_to_nodeindex_t::const_iterator firstiter = 266 _argindex_to_nodeindex.find(_indices.first); 267 ASSERT( firstiter != _argindex_to_nodeindex.end(), 268 "translateIndices() - could not find #"+toString(_indices.first)+ 269 " in translation map."); 270 const argindex_to_nodeindex_t::const_iterator seconditer = 271 _argindex_to_nodeindex.find(_indices.second); 272 ASSERT(seconditer != _argindex_to_nodeindex.end(), 273 "translateIndices() - could not find #"+toString(_indices.second)+ 274 " in translation map."); 275 // mind increasing order of indices in pair 276 if (firstiter->second < seconditer->second) 277 return argument_t::indices_t(firstiter->second, seconditer->second); 278 else 279 return argument_t::indices_t(seconditer->second, firstiter->second); 280 } 281 282 /** Power set generator 283 * 284 * taken from https://rosettacode.org/wiki/Power_set#Non-recursive_version 285 * 286 */ 287 static powerset_type powerset(set_type const& set) 288 { 289 typedef set_type::const_iterator set_iter; 290 typedef std::vector<set_iter> vec; 291 292 struct local 293 { 294 static int dereference(set_iter v) { return *v; } 295 }; 296 297 powerset_type result; 298 299 vec elements; 300 do { 301 set_type tmp; 302 std::transform(elements.begin(), elements.end(), 303 std::inserter(tmp, tmp.end()), 304 local::dereference); 305 result.insert(tmp); 306 if (!elements.empty() && ++elements.back() == set.end()) { 307 elements.pop_back(); 308 } else { 309 set_iter iter; 310 if (elements.empty()) { 311 iter = set.begin(); 312 } else { 313 iter = elements.back(); 314 ++iter; 315 } 316 for (; iter != set.end(); ++iter) { 317 elements.push_back(iter); 318 } 319 } 320 } while (!elements.empty()); 321 322 return result; 323 } 324 325 /** Recursive function to generate all induced, connected subgraphs given a 326 * graph. 327 * 328 * \param N number of still left to pick 329 * \param depth level in \a set_of_nodes 330 * \param nodes current set of nodes that are picked already 331 * \param set_of_nodes resulting set of generated subgraphs' nodes 332 * \param nodes_per_level level-wise frontier of connected nodes around a root node 333 * \param graph graph containing the adjacency 334 * \param index_map with indices per \a graph' vertex 335 */ 336 static void generateAllInducedConnectedSubgraphs( 337 const size_t N, 338 const level_t level, 339 const nodes_t &nodes, 340 set_of_nodes_t &set_of_nodes, 341 const nodes_per_level_t &nodes_per_level, 342 const UndirectedGraph &graph, 343 const std::vector<size_t> &_distance, 344 const index_map_t &index_map) 345 { 346 ASSERT( nodes_per_level.find(level) != nodes_per_level.end(), 347 "generateAllInducedConnectedSubgraphs() - we are deeper than the graph."); 348 ASSERT( N < nodes_per_level.size(), 349 "generateAllInducedConnectedSubgraphs() - we are looking for subgraphs larger than the graph."); 350 if (N > 0) { 351 LOG(3, "DEBUG: At level " << level << " current nodes is " << nodes << ", need to find " << N << " more."); 352 // get next level's set and constrain to nodes connected to this set 353 nodes_t validnodes; 354 std::pair< nodes_per_level_t::const_iterator, nodes_per_level_t::const_iterator> range = 355 nodes_per_level.equal_range(level); 356 for (nodes_per_level_t::const_iterator rangeiter = range.first; 357 rangeiter != range.second; ++rangeiter) { 358 LOG(4, "DEBUG: Checking edges further away from node #" << rangeiter->second); 359 // get all edges connected to this node further away 360 UndirectedGraph::in_edge_iterator i, end; 361 boost::tie(i, end) = boost::in_edges(boost::vertex(rangeiter->second, graph), graph); 362 for (;i != end; ++i) { 363 // check each edge whether it's in nodes 364 const node_t sourceindex = boost::get(index_map, boost::source(*i, graph)); 365 const node_t targetindex = boost::get(index_map, boost::target(*i, graph)); 366 const size_t &source_distance = _distance[sourceindex]; 367 const size_t &target_distance = _distance[targetindex]; 368 // edge is going deeper into graph 369 if (((source_distance == level) && (target_distance == (level+1))) 370 || ((source_distance == (level+1)) && (target_distance == level))) { 371 LOG(5, "DEBUG: Candidate edge on level " << level << " is from " << sourceindex 372 << " to " << targetindex << "."); 373 // pick right index and check for not present in list yet 374 if (sourceindex == rangeiter->second) { 375 if (nodes.count(targetindex) == 0) { 376 validnodes.insert(targetindex); 377 LOG(4, "DEBUG: Inserting node #" << targetindex << " into valid nodes."); 378 } 379 } else if (targetindex == rangeiter->second) { 380 if (nodes.count(sourceindex) == 0) { 381 validnodes.insert(sourceindex); 382 LOG(4, "DEBUG: Inserting node #" << sourceindex << " into valid nodes."); 383 } 384 } else { 385 ASSERT(0, 386 "generateAllInducedConnectedSubgraphs() - neither source #"+toString(sourceindex)+ 387 " nor target #"+toString(targetindex)+" is equal to #"+toString(rangeiter->second)); 388 } 389 } 390 } 391 } 392 // skip this if we cannot go deeper into the graph from here 393 if (validnodes.empty()) { 394 LOG(3, "DEBUG: We did not find any more nodes to step on from " << nodes << "."); 395 return; 396 } 397 398 // go through power set 399 const powerset_type test_powerset = powerset(validnodes); 400 for (powerset_type::const_iterator iter = test_powerset.begin(); 401 iter != test_powerset.end(); 402 ++iter) { 403 // count set bits (#elements in *iter), must be between 1 and N 404 const size_t num_set_bits = iter->size(); 405 if ((num_set_bits > 0) && (num_set_bits <= N)) { 406 // add set to nodes 407 LOG(3, "DEBUG: With present " << nodes << " the current set is " << *iter << " of " 408 << validnodes << "."); 409 410 // copy the nodes before insertion 411 nodes_t filled_nodes(nodes.begin(), nodes.end()); 412 filled_nodes.insert(iter->begin(), iter->end()); 413 414 // and recurse 415 generateAllInducedConnectedSubgraphs( 416 N-num_set_bits, level+1, filled_nodes, set_of_nodes, nodes_per_level, graph, _distance, index_map); 417 } 418 } 419 } else { 420 // N==0: we have a winner 421 std::pair<set_of_nodes_t::iterator, bool> inserter = 422 set_of_nodes.insert( nodes ); 423 if (!inserter.second) 424 LOG(2, "DEBUG: subgraph " << nodes << " is already contained in set_of_nodes."); 425 else 426 LOG(2, "DEBUG: subgraph " << nodes << " inserted into set_of_nodes."); 427 } 428 } 429 430 static Extractors::ParticleType_t getParticleTypeToNode( 431 const type_index_lookup_t &type_index_lookup, 432 const size_t nodeindex) 433 { 434 const type_index_lookup_t::left_const_iterator typeiter = type_index_lookup.left.find(nodeindex); 435 ASSERT( typeiter != type_index_lookup.left.end(), 436 "getParticleTypeToNode() - could not find type to node #"+toString(nodeindex)); 437 return typeiter->second; 438 } 439 440 static HomologyGraph createHomologyGraphFromNodes( 441 const nodes_t &nodes, 442 const type_index_lookup_t &type_index_lookup, 443 const UndirectedGraph &graph, 444 const index_map_t &index_map 445 ) 446 { 447 HomologyGraph::nodes_t graph_nodes; 448 HomologyGraph::edges_t graph_edges; 449 { 450 typedef std::set< std::pair<node_t, node_t> > graph_edges_t; 451 graph_edges_t edge_set; 452 std::pair<HomologyGraph::nodes_t::iterator, bool > inserter; 453 for (nodes_t::const_iterator nodeiter = nodes.begin(); 454 nodeiter != nodes.end(); ++nodeiter) { 455 const Extractors::ParticleType_t &nodetype = getParticleTypeToNode(type_index_lookup, *nodeiter); 456 457 // count edges in constrained set for this particular node 458 size_t num_edges = 0; 459 UndirectedGraph::in_edge_iterator i, end; 460 for (boost::tie(i, end) = boost::in_edges(boost::vertex(*nodeiter, graph), graph); 461 i != end; ++i) { 462 const node_t sourceindex = boost::get(index_map, boost::source(*i, graph)); 463 const node_t targetindex = boost::get(index_map, boost::target(*i, graph)); 464 // check each edge whether it's in nodes 465 if ((nodes.count(sourceindex) != 0) && (nodes.count(targetindex) != 0)) { 466 // increase edge count of node 467 ++num_edges; 468 // we first store edges in a set to ensure their uniqueness (as we encounter 469 // each edge two times and we don't know if source and target will be 470 // different the second time encountered) 471 if (sourceindex < targetindex) 472 edge_set.insert( std::make_pair(sourceindex, targetindex) ); 473 else 474 edge_set.insert( std::make_pair(targetindex, sourceindex) ); 475 } 476 } 477 LOG(4, "DEBUG: Node #" << *nodeiter << " has " << num_edges << " edges."); 478 479 // add FragmentNode 480 inserter = graph_nodes.insert( std::make_pair(FragmentNode(nodetype, num_edges), 1) ); 481 if (!inserter.second) 482 ++(inserter.first->second); 483 } 484 485 // add edges 486 for (graph_edges_t::const_iterator edgeiter = edge_set.begin(); 487 edgeiter != edge_set.end(); ++edgeiter) { 488 const Extractors::ParticleType_t sourcetype = 489 getParticleTypeToNode(type_index_lookup, edgeiter->first); 490 const Extractors::ParticleType_t targettype = 491 getParticleTypeToNode(type_index_lookup, edgeiter->second); 492 // FragmentEdge takes care of proper sorting 493 FragmentEdge edge(sourcetype, targettype); 494 LOG(4, "DEBUG: Adding fragment edge " << edge); 495 std::pair<HomologyGraph::edges_t::iterator, bool > inserter; 496 inserter = graph_edges.insert( std::make_pair( edge, 1) ); 497 if (!inserter.second) 498 ++(inserter.first->second); 499 } 500 } 501 502 return HomologyGraph(graph_nodes, graph_edges); 503 } 504 505 /** 506 * I have no idea why this is so complicated with BGL ... 507 * 508 * This is taken from the book "The Boost Graph Library: User Guide and Reference Manual, Portable Documents", 509 * chapter "Basic Graph Algorithms", example on calculating the bacon number. 510 */ 511 template <typename DistanceMap> 512 class distance_recorder : public boost::default_bfs_visitor 513 { 514 public: 515 distance_recorder(DistanceMap dist) : d(dist) {} 516 517 template <typename Edge, typename Graph> 518 void tree_edge(Edge e, const Graph &g) const { 519 typename boost::graph_traits<Graph>::vertex_descriptor u = source(e,g), v = target(e,g); 520 d[v] = d[u] + 1; 521 } 522 523 private: 524 DistanceMap d; 525 }; 526 527 template <typename DistanceMap> 528 distance_recorder<DistanceMap> record_distance(DistanceMap d) 529 { 530 return distance_recorder<DistanceMap>(d); 531 } 532 163 533 FunctionModel::list_of_arguments_t Extractors::reorderArgumentsByParticleTypes( 164 534 const FunctionModel::list_of_arguments_t &listargs, … … 169 539 { 170 540 FunctionModel::list_of_arguments_t returnargs; 171 for (FunctionModel::list_of_arguments_t::const_iterator iter = listargs.begin(); 172 iter != listargs.end(); ++iter) { 173 const FunctionModel::arguments_t &args = *iter; 174 /// We place all arguments into multimap according to particle type pair. 175 // here, we need a special comparator such that types in key pair are always 176 // properly ordered. 177 typedef std::multimap< 178 argument_t::types_t, 179 argument_t, 180 ParticleTypesComparator> TypePair_Argument_Map_t; 181 TypePair_Argument_Map_t argument_map; 541 for (FunctionModel::list_of_arguments_t::const_iterator listiter = listargs.begin(); 542 listiter != listargs.end(); ++listiter) { 543 const FunctionModel::arguments_t &args = *listiter; 544 545 // deal with the case when there are no distances (ConstantPotential) 546 if (_bindingmodel.getNodes().size() < 2) { 547 LOG(3, "DEBUG: Potential requires only zero or no particle types, needs no distances."); 548 continue; 549 } 550 if (_bindingmodel.getEdges().empty()) { 551 LOG(3, "DEBUG: Potential represents non-bonded interactions, gets all distances."); 552 returnargs.push_back(args); 553 continue; 554 } 555 556 /// 0. place all nodes in a lookup map for their type 557 type_index_lookup_t type_index_lookup; 182 558 for(FunctionModel::arguments_t::const_iterator iter = args.begin(); 183 559 iter != args.end(); ++iter) { 184 argument_map.insert( std::make_pair(iter->types, *iter) ); 185 } 186 LOG(4, "DEBUG: particle_type map is " << argument_map << "."); 187 188 /// Then, we create the desired unique keys 189 typedef std::vector<argument_t::types_t> UniqueTypes_t; 190 UniqueTypes_t UniqueTypes; 191 for (ParticleTypes_t::const_iterator firstiter = _types.begin(); 192 firstiter != _types.end(); 193 ++firstiter) { 194 for (ParticleTypes_t::const_iterator seconditer = firstiter; 195 seconditer != _types.end(); 196 ++seconditer) { 197 if (seconditer == firstiter) 198 continue; 199 UniqueTypes.push_back( std::make_pair(*firstiter, *seconditer) ); 200 } 201 } 202 LOG(4, "DEBUG: Created unique types as keys " << UniqueTypes << "."); 203 204 /// Finally, we use the unique key list to pick corresponding arguments from the map 205 FunctionModel::arguments_t sortedargs; 206 sortedargs.reserve(args.size()); 207 while (!argument_map.empty()) { 208 // note that particle_types_t may be flipped, i.e. 1,8 is equal to 8,1, but we 209 // must maintain the correct order in indices in accordance with the order 210 // in _types, i.e. 1,8,1 must match with e.g. ids 1,0,2 where 1 has type 1, 211 // 0 has type 8, and 2 has type 2. 212 // In other words: We do not want to flip/modify arguments such that they match 213 // with the specific type pair we seek but then this comes at the price that we 214 // have flip indices when the types in a pair are flipped. 215 216 typedef std::vector<size_t> indices_t; 217 //!> here, we gather the indices as we discover them 218 indices_t indices; 219 indices.resize(_types.size(), (size_t)-1); 220 221 // these are two iterators that create index pairs in the same way as we have 222 // created type pairs. If a -1 is still present in indices, then the index is 223 // still arbitrary but is then set by the next found index 224 indices_t::iterator firstindex = indices.begin(); 225 indices_t::iterator secondindex = firstindex+1; 226 227 //!> here, we gather the current bunch of arguments as we find them 228 FunctionModel::arguments_t argumentbunch; 229 argumentbunch.reserve(UniqueTypes.size()); 230 231 for (UniqueTypes_t::const_iterator typeiter = UniqueTypes.begin(); 232 typeiter != UniqueTypes.end(); ++typeiter) { 233 // have all arguments to same type pair as list within the found range 234 std::pair< 235 TypePair_Argument_Map_t::iterator, 236 TypePair_Argument_Map_t::iterator> range_t = 237 argument_map.equal_range(*typeiter); 238 LOG(4, "DEBUG: Set of arguments to current key [" << typeiter->first << "," 239 << typeiter->second << "] is " << std::list<argument_t>( 240 MapValueIterator<TypePair_Argument_Map_t::iterator>(range_t.first), 241 MapValueIterator<TypePair_Argument_Map_t::iterator>(range_t.second) 242 ) << "."); 243 // the first key is always easy and is pivot which the rest has to be associated to 244 if (typeiter == UniqueTypes.begin()) { 245 const argument_t & arg = range_t.first->second; 246 if ((typeiter->first == arg.types.first) && (typeiter->second == arg.types.second)) { 247 // store in correct order 248 *firstindex = arg.indices.first; 249 *secondindex = arg.indices.second; 250 } else { 251 // store in flipped order 252 *firstindex = arg.indices.second; 253 *secondindex = arg.indices.first; 560 if (type_index_lookup.left.find(iter->indices.first) == type_index_lookup.left.end()) 561 type_index_lookup.left.insert( std::make_pair(iter->indices.first, iter->types.first) ); 562 else { 563 ASSERT(type_index_lookup.left.at(iter->indices.first) == iter->types.first, 564 "Extractors::reorderArgumentsByParticleTypes() - entry " +toString(iter->indices.first)+ 565 " is already present with different type "+toString(iter->types.first) 566 +" than "+toString(type_index_lookup.left.at(iter->indices.first))); 567 } 568 if (type_index_lookup.left.find(iter->indices.second) == type_index_lookup.left.end()) 569 type_index_lookup.left.insert( std::make_pair(iter->indices.second, iter->types.second) ); 570 else { 571 ASSERT(type_index_lookup.left.at(iter->indices.second) == iter->types.second, 572 "Extractors::reorderArgumentsByParticleTypes() - entry " +toString(iter->indices.second)+ 573 " is already present with different type "+toString(iter->types.second) 574 +" than "+toString(type_index_lookup.left.at(iter->indices.second))); 575 } 576 } 577 if (DoLog(3)) { 578 std::stringstream output; 579 for (type_index_lookup_t::left_const_iterator indexiter = type_index_lookup.left.begin(); 580 indexiter != type_index_lookup.left.end(); ++indexiter) { 581 output << " [" << indexiter->first << "," << indexiter->second << "]"; 582 } 583 LOG(3, "DEBUG: index to type map:" << output.str()); 584 } 585 if (DoLog(3)) { 586 std::stringstream output; 587 for (type_index_lookup_t::right_const_iterator typeiter = type_index_lookup.right.begin(); 588 typeiter != type_index_lookup.right.end(); ++typeiter) { 589 output << " [" << typeiter->first << "," << typeiter->second << "]"; 590 } 591 LOG(3, "DEBUG: type to index map " << output.str()); 592 } 593 594 /// 1. construct boost::graph from arguments_t (iter) 595 const size_t N = type_index_lookup.left.size(); 596 UndirectedGraph fragmentgraph(N); 597 for(FunctionModel::arguments_t::const_iterator iter = args.begin(); 598 iter != args.end(); ++iter) { 599 if (iter->bonded) 600 boost::add_edge(iter->indices.first, iter->indices.second, fragmentgraph); 601 } 602 index_map_t index_map = boost::get(boost::vertex_index, fragmentgraph); 603 LOG(2, "DEBUG: We have " << boost::num_vertices(fragmentgraph) << " nodes in the fragment graph."); 604 605 /// 2. grab first node of the binding model (gives a type) 606 const FragmentNode &firstnode = _bindingmodel.getNodes().begin()->first; 607 const size_t &firsttimes = _bindingmodel.getNodes().begin()->second; 608 const size_t &firsttype = firstnode.getAtomicNumber(); // TODO: convert to ParticleNumber_t ? 609 610 /// 3. grab all candidate nodes contained in arguments_t 611 std::pair< 612 type_index_lookup_t::right_const_iterator, 613 type_index_lookup_t::right_const_iterator> range = type_index_lookup.right.equal_range(firsttype); 614 #ifndef NDEBUG 615 const size_t checktimes = std::distance(range.first, range.second); 616 ASSERT( firsttimes == checktimes, 617 "Extractors::reorderArgumentsByParticleTypes() - unequal amounts of same first type " 618 +toString(firsttype)+" in HomologyGraph and in type lookup "+toString(checktimes)); 619 #endif 620 621 /// 4. go over all candidate nodes (gives index) 622 set_of_nodes_t set_of_nodes; 623 for (type_index_lookup_t::right_const_iterator rangeiter = range.first; 624 rangeiter != range.second; ++rangeiter) { 625 const size_t &rootindex = rangeiter->second; 626 LOG(2, "DEBUG: Current root index is " << rootindex); 627 628 /// 5a. from node in graph (with this index) perform BFS till n-1 (#nodes in binding model) 629 std::vector<size_t> distances(boost::num_vertices(fragmentgraph)); 630 boost::breadth_first_search( 631 fragmentgraph, 632 boost::vertex(rootindex, fragmentgraph), 633 boost::visitor(record_distance(&distances[0]))); 634 LOG(3, "DEBUG: BFS discovered the following distances " << distances); 635 636 /// 5b. and store all node in map with distance to root as key 637 nodes_per_level_t nodes_per_level; 638 for (size_t i=0;i<distances.size();++i) { 639 nodes_per_level.insert( std::make_pair(level_t(distances[i]), node_t(i)) ); 640 } 641 LOG(3, "DEBUG: Nodes per level are " << nodes_per_level); 642 643 /// 6. construct all possible induced connected subgraphs with this map (see fragmentation) 644 nodes_t nodes; 645 // rootindex is always contained 646 nodes.insert( rootindex ); 647 level_t level = 0; 648 649 generateAllInducedConnectedSubgraphs( 650 N-1, level, nodes, set_of_nodes, nodes_per_level, fragmentgraph, distances, index_map); 651 LOG(2, "DEBUG: We have found " << set_of_nodes.size() << " unique induced, connected subgraphs."); 652 } 653 654 /// 8. go through each induced, connected subgraph 655 for (set_of_nodes_t::const_iterator nodesiter = set_of_nodes.begin(); 656 nodesiter != set_of_nodes.end(); ++nodesiter) { 657 /// 9. convert its nodes into a HomologyGraph using the subgraph and arguments_t (types for index) 658 const nodes_t &nodes = *nodesiter; 659 const HomologyGraph nodes_graph = 660 createHomologyGraphFromNodes(nodes, type_index_lookup, fragmentgraph, index_map); 661 662 /// 10. compare each converted HomologyGraph with _bindingmodel: Accept or Reject 663 if (nodes_graph == _bindingmodel) { 664 LOG(2, "ACCEPT: " << nodes_graph << " is identical to " << _bindingmodel); 665 /// 11. for each accepted keyset, pick _all_ symmetric distances from arguments_t 666 FunctionModel::arguments_t argumentbunch; 667 argumentbunch.reserve(args.size()); 668 for(FunctionModel::arguments_t::const_iterator iter = args.begin(); 669 iter != args.end(); ++iter) { 670 if ((nodes.count(iter->indices.first) != 0) && (nodes.count(iter->indices.second) != 0)) { 671 argumentbunch.push_back(*iter); 254 672 } 255 argumentbunch.push_back(arg); 256 argument_map.erase(range_t.first); 257 LOG(4, "DEBUG: Gathered first argument " << arg << "."); 258 } else { 259 // go through the range and pick the first argument matching the index constraints 260 for (TypePair_Argument_Map_t::iterator argiter = range_t.first; 261 argiter != range_t.second; ++argiter) { 262 // seconditer may be -1 still 263 const argument_t &arg = argiter->second; 264 if (arg.indices.first == *firstindex) { 265 if ((arg.indices.second == *secondindex) || (*secondindex == (size_t)-1)) { 266 if (*secondindex == (size_t)-1) 267 *secondindex = arg.indices.second; 268 argumentbunch.push_back(arg); 269 argument_map.erase(argiter); 270 LOG(4, "DEBUG: Gathered another argument " << arg << "."); 271 break; 272 } 273 } else if ((arg.indices.first == *secondindex) || (*secondindex == (size_t)-1)) { 274 if (arg.indices.second == *firstindex) { 275 if (*secondindex == (size_t)-1) 276 *secondindex = arg.indices.first; 277 argumentbunch.push_back(arg); 278 argument_map.erase(argiter); 279 LOG(4, "DEBUG: Gathered another (flipped) argument " << arg << "."); 673 } 674 const size_t num_symmetric_distances = nodes.size()*(nodes.size()-1)/2; 675 ASSERT( argumentbunch.size() == num_symmetric_distances, 676 "Extractors::reorderArgumentsByParticleTypes() - only "+toString(argumentbunch.size())+ 677 " found instead of "+toString(num_symmetric_distances)); 678 LOG(3, "DEBUG: Final bunch of arguments is " << argumentbunch << "."); 679 680 /** 681 * We still need to bring the arguments in the correct order for the potential. 682 * 683 * The potential gives the desired order via the nodes in the HomologyGraph! Their 684 * sequence matches with the user-defined particle types and because of the properties 685 * of the homology graph (FragmentNode stores type and number of edges) it also 686 * matches with the desired bonding graph. 687 */ 688 689 /// So, we need to store for each node its type and the number of connected 690 /// edges, which we extract from the argumentbunch. 691 node_FragmentNode_map_t node_FragmentNode_map = fillNodeFragmentMap(argumentbunch); 692 693 /// Then, we step through the nodes of the bindingmodel 694 const HomologyGraph::nodes_t bindingmodel_nodes = _bindingmodel.getNodes(); 695 argindex_to_nodeindex_t argindex_to_nodeindex; 696 size_t nodeindex = 0; 697 for (HomologyGraph::nodes_t::const_iterator nodeiter = bindingmodel_nodes.begin(); 698 nodeiter != bindingmodel_nodes.end(); ++nodeiter) { 699 const FragmentNode &node = nodeiter->first; 700 LOG(3, "DEBUG: Binding model's node #" << node << "."); 701 // might have to pick several 702 for (size_t pick_no = 0; pick_no < nodeiter->second; ++pick_no) { 703 /// ... and pick for each the first (and unique) from these stored nodes. 704 node_FragmentNode_map_t::iterator mapiter = node_FragmentNode_map.begin(); 705 for (;mapiter != node_FragmentNode_map.end(); ++mapiter) { 706 if ((mapiter->second.first == node.getAtomicNumber()) 707 && (mapiter->second.second == node.getConnectedEdges())) { 708 LOG(3, "DEBUG: #" << mapiter->first << " with type " << mapiter->second.first 709 << " and " << mapiter->second.second << " connected edges matches as choice #" 710 << pick_no << "."); 280 711 break; 281 712 } 282 713 } 714 ASSERT( mapiter != node_FragmentNode_map.end(), 715 "Extractors::reorderArgumentsByParticleTypes() - could not find a suitable node for #"+ 716 toString(mapiter->first)+" with type "+toString(mapiter->second.first)+" and "+ 717 toString(mapiter->second.second)+" connected edges"); 718 std::pair<argindex_to_nodeindex_t::iterator, bool> inserter = 719 argindex_to_nodeindex.insert( std::make_pair(mapiter->first, nodeindex++) ); 720 ASSERT( inserter.second, 721 "Extractors::reorderArgumentsByParticleTypes() - node #"+toString(mapiter->first)+ 722 " is already present?"); 723 // remove to ensure uniqueness of choice 724 node_FragmentNode_map.erase(mapiter); 283 725 } 284 726 } 285 // move along in indices and check bounds 286 ++secondindex; 287 if (secondindex == indices.end()) { 288 ++firstindex; 289 if (firstindex != indices.end()-1) 290 secondindex = firstindex+1; 727 /// This gives then the desired mapping from indices in the arguments to 728 /// the index in the order of the HomologyGraph's nodes 729 730 /// Finally, we only need to bring the arguments in the typical order: 731 /// 01 02 03 04 ... 0n, 12 13 14 ... 1n, 23 24 25 ... 2n, ..., (n-1)n 732 const size_t num_args = argindex_to_nodeindex.size(); 733 argument_placement_map_t argument_placement_map = fillArgumentsPlacementMap(num_args); 734 LOG(4, "DEBUG: Placement map is " << argument_placement_map); 735 ASSERT( argument_placement_map.size() == argumentbunch.size(), 736 "Extractors::reorderArgumentsByParticleTypes() - placement map has size "+ 737 toString(argument_placement_map.size())+" and we expected "+toString(argumentbunch.size())); 738 739 // and finally resort the arguments with the known placement map 740 FunctionModel::arguments_t sortedargs(argumentbunch); 741 for (FunctionModel::arguments_t::const_iterator argiter = argumentbunch.begin(); 742 argiter != argumentbunch.end(); ++argiter) { 743 const argument_t &arg = *argiter; 744 const argument_placement_map_t::const_iterator indexiter = 745 argument_placement_map.find( translateIndices(argindex_to_nodeindex, arg.indices) ); 746 ASSERT( indexiter != argument_placement_map.end(), 747 "Extractors::reorderArgumentsByParticleTypes() - could not find place for edge "+ 748 toString(arg.indices)); 749 sortedargs[indexiter->second] = arg; 750 LOG(3, "DEBUG: Placed argument " << arg << " at #" << indexiter->second 751 << " as translated indices are " << translateIndices(argindex_to_nodeindex, arg.indices)); 291 752 } 292 } 293 ASSERT( (firstindex == indices.end()-1) && (secondindex == indices.end()), 294 "Extractors::reorderArgumentsByParticleTypes() - we have not gathered enough arguments."); 295 ASSERT( argumentbunch.size() == UniqueTypes.size(), 296 "Extractors::reorderArgumentsByParticleTypes() - we have not gathered enough arguments."); 297 // place bunch of arguments in return args 298 LOG(3, "DEBUG: Given types " << _types << " and found indices " << indices << "."); 299 LOG(3, "DEBUG: Final bunch of arguments is " << argumentbunch << "."); 300 sortedargs.insert(sortedargs.end(), argumentbunch.begin(), argumentbunch.end()); 301 } 302 returnargs.push_back(sortedargs); 753 LOG(2, "DEBUG: Sorted arguments are " << sortedargs << "."); 754 755 returnargs.push_back(sortedargs); 756 } else { 757 LOG(2, "REJECT: " << nodes_graph << " is not identical to " << _bindingmodel); 758 } 759 } 303 760 } 304 761 … … 368 825 FunctionModel::list_of_arguments_t singlelist_allargs; 369 826 singlelist_allargs.push_back(allargs); 370 FunctionModel::list_of_arguments_t sortedargs =827 FunctionModel::list_of_arguments_t returnargs = 371 828 reorderArgumentsByParticleTypes(singlelist_allargs, _graph, _types, _bindingmodel); 372 ASSERT( sortedargs.size() == (size_t)1,373 "Extractors::filterArgumentsByParticleTypes() - reordering did not generate a single list.");374 // then we split up the tuples of arguments and place each into single list375 FunctionModel::list_of_arguments_t returnargs;376 FunctionModel::arguments_t::const_iterator argiter = sortedargs.begin()->begin();377 const size_t num_types = _types.size();378 const size_t args_per_tuple = num_types * (num_types-1) / 2;379 while (argiter != sortedargs.begin()->end()) {380 FunctionModel::arguments_t currenttuple(args_per_tuple);381 const FunctionModel::arguments_t::const_iterator startiter = argiter;382 std::advance(argiter, args_per_tuple);383 #ifndef NDEBUG384 FunctionModel::arguments_t::const_iterator endoutiter =385 #endif386 std::copy(startiter, argiter, currenttuple.begin());387 ASSERT( endoutiter == currenttuple.end(),388 "Extractors::filterArgumentsByParticleTypes() - currenttuple not initialized to right size.");389 returnargs.push_back(currenttuple);390 }829 // ASSERT( sortedargs.size() == (size_t)1, 830 // "Extractors::filterArgumentsByParticleTypes() - reordering did not generate a single list."); 831 // // then we split up the tuples of arguments and place each into single list 832 // FunctionModel::list_of_arguments_t returnargs; 833 // FunctionModel::arguments_t::const_iterator argiter = sortedargs.begin()->begin(); 834 // const size_t num_types = _types.size(); 835 // const size_t args_per_tuple = num_types * (num_types-1) / 2; 836 // while (argiter != sortedargs.begin()->end()) { 837 // FunctionModel::arguments_t currenttuple(args_per_tuple); 838 // const FunctionModel::arguments_t::const_iterator startiter = argiter; 839 // std::advance(argiter, args_per_tuple); 840 //#ifndef NDEBUG 841 // FunctionModel::arguments_t::const_iterator endoutiter = 842 //#endif 843 // std::copy(startiter, argiter, currenttuple.begin()); 844 // ASSERT( endoutiter == currenttuple.end(), 845 // "Extractors::filterArgumentsByParticleTypes() - currenttuple not initialized to right size."); 846 // returnargs.push_back(currenttuple); 847 // } 391 848 392 849 LOG(2, "DEBUG: We have generated " << returnargs.size() << " tuples of distances."); -
src/FunctionApproximation/unittests/ExtractorsUnitTest.cpp
r228340 r2124aa 98 98 CPPUNIT_ASSERT( (args[i].distance >= 0) && (args[i].distance <= 4)); 99 99 } 100 101 /** UnitTest for gatherAllSymmetricDistances() with edges 102 */ 103 void ExtractorsTest::gatherAllSymmetricDistances_edgesTest() 104 { 105 // create positions 106 Fragment::positions_t positions; 107 Fragment::position_t pos(3, 0.); 108 for (double i = 0; i < 5; i+=1.) { 109 pos[0] = i; 110 positions.push_back(pos); 111 } 112 FragmentationEdges::edges_t edges; 113 for (size_t i=1;i<5;++i) 114 edges += FragmentationEdges::edge_t(i-1, i); 115 116 // create charges 117 Fragment::atomicnumbers_t atomicnumbers; 118 atomicnumbers += 6, 6, 1, 1, 1; 119 120 // create distances 121 FunctionModel::arguments_t args = 122 Extractors::gatherAllSymmetricDistances(positions, atomicnumbers, edges, 0); 123 CPPUNIT_ASSERT_EQUAL( (size_t)(5*4/2), args.size() ); 124 125 // check created args 126 for (size_t i=0; i< 5*4/2; ++i) { 127 CPPUNIT_ASSERT( (args[i].distance >= 0) && (args[i].distance <= 4)); 128 if ((args[i].indices.first+1) == args[i].indices.second) 129 CPPUNIT_ASSERT( args[i].bonded ); 130 } 131 } -
src/FunctionApproximation/unittests/ExtractorsUnitTest.hpp
r228340 r2124aa 23 23 CPPUNIT_TEST_SUITE( ExtractorsTest) ; 24 24 CPPUNIT_TEST ( gatherAllSymmetricDistancesTest ); 25 CPPUNIT_TEST ( gatherAllSymmetricDistances_edgesTest ); 25 26 CPPUNIT_TEST_SUITE_END(); 26 27 … … 29 30 void tearDown(); 30 31 void gatherAllSymmetricDistancesTest(); 32 void gatherAllSymmetricDistances_edgesTest(); 31 33 32 34 private: -
src/FunctionApproximation/unittests/Makefile.am
r228340 r2124aa 20 20 FUNCTIONAPPROXIMATIONLIBS = \ 21 21 libUnitTest.la \ 22 ../libMolecuilder.la \23 22 ../libMolecuilderFunctionApproximation.la \ 23 ../libMolecuilderFragmentation.la \ 24 ../libMolecuilderFragmentation_getFromKeysetStub.la \ 24 25 $(top_builddir)/LinearAlgebra/src/LinearAlgebra/libLinearAlgebra.la \ 25 26 ${CodePatterns_LIBS} \
Note:
See TracChangeset
for help on using the changeset viewer.