Changeset 99c705 for src/Actions
- Timestamp:
- Jun 22, 2018, 7:26:30 AM (7 years ago)
- Branches:
- Candidate_v1.6.1, ChemicalSpaceEvaluator
- Children:
- d661b2
- Parents:
- f5ea10
- git-author:
- Frederik Heber <frederik.heber@…> (10/01/17 11:02:10)
- git-committer:
- Frederik Heber <frederik.heber@…> (06/22/18 07:26:30)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/Actions/GraphAction/ChemicalSpaceEvaluatorAction.cpp
rf5ea10 r99c705 36 36 37 37 #include <iostream> 38 #include <list> 39 #include <map> 38 40 #include <string> 39 41 #include <vector> 42 43 #include <boost/graph/copy.hpp> 40 44 41 45 #include "CodePatterns/Log.hpp" … … 57 61 #include "Action_impl_pre.hpp" 58 62 /** =========== define the function ====================== */ 63 template<class map_t, class key_t> 64 static int getElementFromMap( 65 const map_t &_map, 66 const key_t &_keyname) 67 { 68 typename map_t::const_iterator iter = _map.find(_keyname); 69 ASSERT( iter != _map.end(), 70 "getElementFromMap() - cannot find key "+toString(_keyname)+" in map."); 71 return iter->second; 72 } 73 74 typedef std::pair<BoostGraphCreator::Vertex, BoostGraphCreator::Vertex> edge_by_vertices_t; 75 typedef std::map<edge_by_vertices_t, int> edge_valence_t; 76 typedef std::vector<edge_by_vertices_t> edges_t; 77 typedef std::vector<int> degrees_t; 78 typedef std::list< degrees_t > list_of_edge_degrees_t; 79 typedef std::map< unsigned int, int> type_valence_map_t; 80 typedef std::map< edge_by_vertices_t , size_t> edge_index_t; 81 82 static int powerset_edge_degree( 83 list_of_edge_degrees_t &list_of_edge_degrees, 84 degrees_t ¤t_degrees, 85 const size_t remaining_edges, 86 const size_t current_index, 87 const edges_t &edges, 88 const edge_valence_t &edge_valence) 89 { 90 if (remaining_edges == 0) { 91 list_of_edge_degrees.push_back(current_degrees); 92 LOG(3, "DEBUG: Adding [" << current_degrees << "] list of degrees."); 93 return 1; 94 } else { 95 size_t no_combinations = 0; 96 // get valence 97 const edge_by_vertices_t &e = edges[current_index]; 98 const int current_max_degree = getElementFromMap< 99 edge_valence_t, 100 edge_by_vertices_t>(edge_valence, e); 101 // create all combinations and recurse 102 for(current_degrees[current_index] = 1; 103 current_degrees[current_index] <= current_max_degree; 104 ++current_degrees[current_index]) { 105 no_combinations += powerset_edge_degree( 106 list_of_edge_degrees, current_degrees, 107 remaining_edges-1, current_index+1, 108 edges, edge_valence); 109 } 110 return no_combinations; 111 } 112 } 113 114 static int getValenceForVertex( 115 const BoostGraphCreator::name_map_t &name_map, 116 const Extractors::type_index_lookup_t &type_index_lookup, 117 const type_valence_map_t &type_valence_map, 118 const BoostGraphCreator::Vertex &v 119 ) 120 { 121 const atomId_t atomid_v = boost::get(name_map, v); 122 const Extractors::type_index_lookup_t::left_const_iterator iter_v = type_index_lookup.left.find(atomid_v); 123 ASSERT( iter_v != type_index_lookup.left.end(), 124 "getValenceForVertex() - cannot find "+toString(atomid_v)); 125 const unsigned int elementno_v = iter_v->second; 126 return getElementFromMap<type_valence_map_t, unsigned int>(type_valence_map, elementno_v); 127 } 128 129 static edge_by_vertices_t getEdgeByVertices( 130 const BoostGraphCreator::Vertex& u, 131 const BoostGraphCreator::Vertex& v) 132 { 133 if (u < v) 134 return std::make_pair(u,v); 135 else 136 return std::make_pair(v,u); 137 } 138 139 static edge_by_vertices_t getEdgeVerticesByEdge( 140 const BoostGraphCreator::Edge& e, 141 const BoostGraphCreator::UndirectedGraph &graph) 142 { 143 const BoostGraphCreator::Vertex u = source(e, graph); 144 const BoostGraphCreator::Vertex v = source(e, graph); 145 return getEdgeByVertices(u,v); 146 } 147 148 149 struct SaturatedGraph 150 { 151 //!> states whether each node fulfills the octet rule, i.e. has bonds weight by their degree equal to its valence 152 bool ValencesAllFulfilled; 153 //!> graph saturated with additional hydrogens 154 BoostGraphCreator::UndirectedGraph saturated_graph; 155 //!> type per edge in the graph 156 Extractors::type_index_lookup_t type_index_lookup; 157 }; 158 159 template <class graph_type> 160 static SaturatedGraph saturateGraph( 161 const graph_type &graph, 162 const Extractors::nodes_t &nodes, 163 const BoostGraphCreator::name_map_t &name_map, 164 const Extractors::type_index_lookup_t &type_index_lookup, 165 const type_valence_map_t &type_valence_map, 166 const edge_index_t &edge_index, 167 const edges_t &edges, 168 const degrees_t °rees 169 ) 170 { 171 SaturatedGraph newgraph; 172 boost::copy_graph(graph, newgraph.saturated_graph); 173 newgraph.ValencesAllFulfilled = true; 174 175 // need to translate type_index_lookup as Extractors::createHomologyKey..() only 176 // looks at the vertex index, not its name. When extracting the subgraph, we 177 // might extract node #1, but insert it as new node index #0. Therefore, we have 178 // to translate all indices in the lookup 179 const Extractors::index_map_t index_map = boost::get(boost::vertex_index, graph); 180 { 181 BoostGraphCreator::vertex_iter vp, vpend; 182 for (boost::tie(vp, vpend) = vertices(graph); vp != vpend; ++vp) { 183 BoostGraphCreator::Vertex v = *vp; 184 const atomId_t vindex = boost::get(name_map, v); 185 Extractors::type_index_lookup_t::left_const_iterator iter = type_index_lookup.left.find(vindex); 186 if (iter != type_index_lookup.left.end()) { 187 const Extractors::node_t nodeid = boost::get(index_map, v); 188 newgraph.type_index_lookup.left.insert( std::make_pair(nodeid, iter->second) ); 189 LOG(4, "DEBUG: Adding type to index lookup for vertex " << iter->first); 190 } 191 } 192 } 193 194 size_t no_nodes = boost::num_vertices(newgraph.saturated_graph); 195 // step through every node, sum up its degrees 196 BoostGraphCreator::vertex_iter vp, vpend; 197 for (boost::tie(vp, vpend) = vertices(graph); vp != vpend; ++vp) { 198 BoostGraphCreator::Vertex v = *vp; 199 const atomId_t vindex = boost::get(name_map, v); 200 LOG(3, "DEBUG: Current vertex is #" << vindex); 201 const int max_valence = getValenceForVertex(name_map, type_index_lookup, type_valence_map, v); 202 int total_valence = 0; 203 typename boost::graph_traits<graph_type>::out_edge_iterator i, end; 204 for (boost::tie(i, end) = boost::out_edges(v, graph); i != end; ++i) { 205 const BoostGraphCreator::Edge &e = *i; 206 const BoostGraphCreator::Vertex e1 = source(e, graph); 207 const BoostGraphCreator::Vertex e2 = target(e, graph); 208 const edge_by_vertices_t edge_by_vertices = getEdgeByVertices(e1,e2); 209 LOG(3, "DEBUG: Current edge is (" << edge_by_vertices << ")"); 210 const size_t index = getElementFromMap<edge_index_t, edge_by_vertices_t>( 211 edge_index, edge_by_vertices); 212 ASSERT( index < edges.size(), 213 "saturateGraph() - index "+toString(index)+" out of range [0, " 214 +toString(edges.size())+"]"); 215 total_valence += degrees[index]; 216 } 217 LOG(3, "DEBUG: Vertex #" << vindex << " has total valence of " 218 << total_valence << " and " << max_valence << " max valence."); 219 // add hydrogens till valence is depleted 220 newgraph.ValencesAllFulfilled &= (total_valence <= max_valence); 221 for (int remaining_valence = total_valence; remaining_valence < max_valence; 222 ++remaining_valence) { 223 // add hydrogen node to this node 224 LOG(4, "DEBUG: Adding node " << no_nodes << " with type " << Extractors::ParticleType_t(1)); 225 newgraph.type_index_lookup.left.insert( 226 std::make_pair(no_nodes, Extractors::ParticleType_t(1))); 227 BoostGraphCreator::Vertex h = boost::add_vertex(no_nodes, newgraph.saturated_graph); 228 ++no_nodes; 229 230 // add edge to hydrogen 231 std::pair<BoostGraphCreator::Edge, bool> edge_inserter = 232 boost::add_edge(v, h, newgraph.saturated_graph); 233 } 234 LOG(2, "DEBUG: Added " << (max_valence - total_valence) 235 << " hydrogens to vertex #" << vindex); 236 } 237 238 return newgraph; 239 } 240 241 template <typename graph_t> 242 BoostGraphCreator::UndirectedGraph extractSubgraph( 243 const graph_t &_graph, 244 const Extractors::nodes_t &nodes) 245 { 246 BoostGraphCreator::UndirectedGraph subgraph; 247 const Extractors::index_map_t index_map = boost::get(boost::vertex_index, _graph); 248 249 // add nodes 250 BoostGraphCreator::vertex_iter viter, vend; 251 for (boost::tie(viter, vend) = boost::vertices(_graph); viter != vend; ++viter) { 252 const size_t nodeid = boost::get(index_map, *viter); 253 if (nodes.find(nodeid) != nodes.end()) { 254 boost::add_vertex(*viter, subgraph); 255 LOG(4, "DEBUG: Adding node " << *viter << " to subgraph."); 256 } 257 } 258 259 // add edges 260 for (boost::tie(viter, vend) = boost::vertices(_graph); viter != vend; ++viter) { 261 BoostGraphCreator::UndirectedGraph::in_edge_iterator i, end; 262 for (boost::tie(i, end) = boost::in_edges(boost::vertex(*viter, _graph), _graph); 263 i != end; ++i) { 264 const Extractors::node_t sourceindex = boost::get(index_map, boost::source(*i, _graph)); 265 const Extractors::node_t targetindex = boost::get(index_map, boost::target(*i, _graph)); 266 if ((nodes.find(sourceindex) != nodes.end()) && (nodes.find(targetindex) != nodes.end()) 267 && (sourceindex < targetindex)) { 268 boost::add_edge(sourceindex, targetindex, subgraph); 269 LOG(4, "DEBUG: Adding edge " << sourceindex << "<->" << targetindex << " to subgraph."); 270 } 271 } 272 } 273 274 return subgraph; 275 } 276 277 59 278 ActionState::ptr GraphChemicalSpaceEvaluatorAction::performCall() { 60 // create boost::graph from graph6 string279 /// 1. create boost::graph from graph6 string 61 280 BoostGraphCreator BGC; 62 281 BGC.createFromGraph6String(params.graph_string.get()); … … 65 284 66 285 Extractors::index_map_t index_map = boost::get(boost::vertex_index, graph); 67 LOG( 2, "DEBUG: We have " << boost::num_vertices(graph) << " nodes in the fragment graph.");68 69 // associate type with a node index286 LOG(1, "INFO: We have " << boost::num_vertices(graph) << " nodes in the fragment graph."); 287 288 /// 2. associate type with a node index 70 289 Extractors::type_index_lookup_t type_index_lookup; 71 290 std::vector<unsigned int> elementnumbers; 72 291 elementnumbers.reserve(params.graph_elements.get().size()); 292 size_t i = 0; 73 293 for (std::vector<const element *>::const_iterator iter = params.graph_elements.get().begin(); 74 294 iter != params.graph_elements.get().end(); ++iter) { 75 295 elementnumbers.push_back((*iter)->getAtomicNumber()); 296 LOG(3, "DEBUG: Adding [" << i << ", " << elementnumbers.back() << "] type to index lookup."); 76 297 type_index_lookup.left.insert( 77 std::make_pair( 78 std::distance(iter, params.graph_elements.get().begin()), 79 Extractors::ParticleType_t(elementnumbers.back()))); 80 } 81 82 // create all induced subgraphs 298 std::make_pair(i++, Extractors::ParticleType_t(elementnumbers.back()))); 299 } 300 if (i != boost::num_vertices(graph)) { 301 ELOG(1, "Not enough elements given."); 302 return Action::failure; 303 } 304 305 /// 3a. get range of valence for each node 306 type_valence_map_t type_valence_map; 307 for (std::vector<const element *>::const_iterator iter = params.graph_elements.get().begin(); 308 iter != params.graph_elements.get().end(); ++iter) { 309 if (type_valence_map.count((*iter)->getAtomicNumber()) == 0) { 310 LOG(3, "DEBUG: Adding [" << (*iter)->getAtomicNumber() 311 << ", " << (*iter)->getNoValenceOrbitals() << "] type to valence lookup."); 312 type_valence_map.insert( std::make_pair( 313 (*iter)->getAtomicNumber(), 314 (*iter)->getNoValenceOrbitals()) ); 315 } 316 } 317 318 // get map for retrieving vertex index for a given vertex 319 const BoostGraphCreator::name_map_t name_map = boost::get(boost::vertex_name, graph); 320 321 /// 3b. generate range of degree for each edge 322 edge_valence_t edge_valence; 323 edges_t edges; 324 edge_index_t edge_index; 325 edges.reserve(boost::num_edges(graph)); 326 { 327 size_t index = 0; 328 BoostGraphCreator::edge_iter i, end; 329 for (boost::tie(i, end) = boost::edges(graph); i != end; ++i) { 330 static int MAX_DEGREE = 3; 331 const BoostGraphCreator::Edge &e = *i; 332 /// 4a. place all edges into a vector 333 const BoostGraphCreator::Vertex u = source(e, graph); 334 const BoostGraphCreator::Vertex v = target(e, graph); 335 const edge_by_vertices_t edge_by_vertices = getEdgeByVertices(u,v); 336 edges.push_back(edge_by_vertices); 337 edge_index.insert( std::make_pair( 338 edge_by_vertices, index++) ); 339 const int valence_u = getValenceForVertex(name_map, type_index_lookup, type_valence_map, u); 340 const int valence_v = getValenceForVertex(name_map, type_index_lookup, type_valence_map, v); 341 const int max_degree = std::max(1, 342 std::min( 343 std::min(valence_u, MAX_DEGREE), 344 std::min(valence_v, MAX_DEGREE) 345 )); 346 edge_valence.insert( 347 std::make_pair(edge_by_vertices, max_degree) 348 ); 349 LOG(3, "DEBUG: Adding [" << std::make_pair(u,v) << ", " 350 << max_degree << "] edge to valence lookup."); 351 } 352 } 353 354 /// 4. for each graph with type per node and degree per edge set, add hydrogen nodes and edges 355 // go through powerset over all edges 356 357 /// 4b. have a recursive function that puts together the powerset over all max_degree 358 list_of_edge_degrees_t list_of_edge_degrees; 359 size_t no_combinations = 0; 360 { 361 size_t remaining_edges = edges.size(); 362 size_t current_index = 0; 363 degrees_t current_degrees(edges.size(), 0); 364 no_combinations = powerset_edge_degree( 365 list_of_edge_degrees, current_degrees, 366 remaining_edges, current_index, 367 edges, edge_valence); 368 } 369 LOG(1, "INFO: Added " << no_combinations << " graph degree combinations."); 370 371 /// 5. dissect graph into a list of subgraphs 372 typedef std::vector<BoostGraphCreator::UndirectedGraph> subgraphs_t; 373 subgraphs_t allsubgraphs; 83 374 const size_t nodes_in_graph = boost::num_vertices(graph); 84 375 LOG(2, "DEBUG: There are " << nodes_in_graph << " nodes in the graph."); … … 103 394 LOG(3, "DEBUG: Nodes per level are " << nodes_per_level); 104 395 105 /// 6. construct all possible induced connected subgraphs with this map (see fragmentation)396 /// 5c. construct all possible induced connected subgraphs with this map (see fragmentation) 106 397 Extractors::nodes_t nodes; 107 398 // rootindex is always contained … … 109 400 Extractors::level_t level = 0; 110 401 111 Extractors::generateAllInducedConnectedSubgraphs( 112 nodes_in_graph-1, level, nodes, set_of_nodes, nodes_per_level, graph, distances, index_map); 402 for (size_t i=0;i<nodes_in_graph; ++i) 403 Extractors::generateAllInducedConnectedSubgraphs( 404 i, level, nodes, set_of_nodes, nodes_per_level, graph, distances, index_map); 113 405 LOG(2, "DEBUG: We have found " << set_of_nodes.size() << " unique induced, connected subgraphs."); 114 406 } 115 407 408 typedef std::vector< 409 std::pair< 410 BoostGraphCreator::UndirectedGraph, 411 degrees_t> > graphs_with_degrees_t; 412 413 // 6. for every combination saturate fragments for lookup and energy contribution summation 116 414 const HomologyContainer &container = World::getInstance().getHomologies(); 117 /// go through each induced, connected subgraph 118 for (Extractors::set_of_nodes_t::const_iterator nodesiter = set_of_nodes.begin(); 119 nodesiter != set_of_nodes.end(); ++nodesiter) { 120 /// convert its nodes into a HomologyGraph using the graph and elements (types for index) 121 const Extractors::nodes_t &nodes = *nodesiter; 122 const HomologyGraph nodes_graph = 123 Extractors::createHomologyGraphFromNodes(nodes, type_index_lookup, graph, index_map); 124 125 /// Query HomologyContainer for this HomologyGraph. 126 HomologyContainer::range_t range = container.getHomologousGraphs(nodes_graph); 127 128 if (range.first == range.second) { 129 // range is empty, the fragment is unknown 130 ELOG(1, "Cannot find fragment graph " << nodes_graph << " to graph " << elementnumbers); 131 } else { 132 // list first energy 133 LOG(1, "Fragment graph " << nodes_graph << " has energy " << range.first->second.energy); 134 } 415 for (list_of_edge_degrees_t::const_iterator degrees_iter = list_of_edge_degrees.begin(); 416 degrees_iter != list_of_edge_degrees.end(); ++degrees_iter) { 417 const degrees_t ¤t_degrees = *degrees_iter; 418 419 // simply sum up the contributions from all fragments for the total energy 420 // of this particular combination, given the graph, the element for each node, 421 // and the bond degrees for each edge 422 double total_energy = 0.; 423 424 // get fragment 425 for (Extractors::set_of_nodes_t::const_iterator nodesiter = set_of_nodes.begin(); 426 nodesiter != set_of_nodes.end(); ++nodesiter) { 427 const Extractors::nodes_t ¤t_nodes = *nodesiter; 428 LOG(2, "DEBUG: Nodes for graph are " << current_nodes); 429 430 // create subgraph 431 Extractors::UndirectedGraph newgraph = extractSubgraph(graph, current_nodes); 432 433 const BoostGraphCreator::name_map_t new_name_map = 434 boost::get(boost::vertex_name, newgraph); 435 { 436 BoostGraphCreator::vertex_iter viter, vend; 437 boost::tie(viter, vend) = boost::vertices(newgraph); 438 for (; viter != vend; ++viter) { 439 const atomId_t vindex = boost::get(new_name_map, *viter); 440 LOG(4, "DEBUG: Copied node has index " << vindex); 441 } 442 } 443 444 // saturate subgraph: add to nodes, add to type_index_lookup, index_map 445 // saturate any leftover valence with hydrogen nodes 446 SaturatedGraph fullgraph = 447 saturateGraph(newgraph, current_nodes, new_name_map, 448 type_index_lookup, type_valence_map, edge_index, 449 edges, current_degrees); 450 451 // don't add if one of the node's valence cannot be fulfilled 452 if (!fullgraph.ValencesAllFulfilled) 453 continue; 454 455 const Extractors::index_map_t subgraph_index_map = 456 boost::get(boost::vertex_index, fullgraph.saturated_graph); 457 const BoostGraphCreator::name_map_t subgraph_name_map = 458 boost::get(boost::vertex_name, fullgraph.saturated_graph); 459 460 Extractors::nodes_t saturated_nodes; 461 BoostGraphCreator::vertex_iter viter, vend; 462 boost::tie(viter, vend) = boost::vertices(fullgraph.saturated_graph); 463 for (; viter != vend; ++viter) { 464 const Extractors::node_t vindex = boost::get(subgraph_index_map, *viter); 465 LOG(4, "DEBUG: Adding node index " << vindex << " to saturated nodes list."); 466 saturated_nodes.insert(vindex); 467 } 468 /// convert its nodes into a HomologyGraph using the graph and elements (types for index) 469 const HomologyGraph nodes_graph = 470 Extractors::createHomologyGraphFromNodes( 471 saturated_nodes, 472 fullgraph.type_index_lookup, 473 fullgraph.saturated_graph, 474 subgraph_index_map); 475 LOG(2, "DEBUG: Looking for graph " << nodes_graph); 476 477 /// Query HomologyContainer for this HomologyGraph. 478 HomologyContainer::range_t range = container.getHomologousGraphs(nodes_graph); 479 480 if (range.first == range.second) { 481 // range is empty, the fragment is unknown 482 ELOG(1, "Cannot find fragment graph " << nodes_graph << " to graph " << elementnumbers); 483 } else { 484 // list first energy 485 LOG(1, "Fragment graph " << nodes_graph << " has contribution " << range.first->second.energy); 486 total_energy += range.first->second.energy; 487 } 488 } 489 LOG(1, "The graph with degrees " << *degrees_iter << " has a total energy of " << total_energy); 135 490 } 136 491
Note:
See TracChangeset
for help on using the changeset viewer.