Changeset 99c705 for src/Actions


Ignore:
Timestamp:
Jun 22, 2018, 7:26:30 AM (7 years ago)
Author:
Frederik Heber <frederik.heber@…>
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)
Message:

ChemicalSpaceEvaluator working for graph with 2 nodes.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/Actions/GraphAction/ChemicalSpaceEvaluatorAction.cpp

    rf5ea10 r99c705  
    3636
    3737#include <iostream>
     38#include <list>
     39#include <map>
    3840#include <string>
    3941#include <vector>
     42
     43#include <boost/graph/copy.hpp>
    4044
    4145#include "CodePatterns/Log.hpp"
     
    5761#include "Action_impl_pre.hpp"
    5862/** =========== define the function ====================== */
     63template<class map_t, class key_t>
     64static 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
     74typedef std::pair<BoostGraphCreator::Vertex, BoostGraphCreator::Vertex> edge_by_vertices_t;
     75typedef std::map<edge_by_vertices_t, int> edge_valence_t;
     76typedef std::vector<edge_by_vertices_t> edges_t;
     77typedef std::vector<int> degrees_t;
     78typedef std::list< degrees_t > list_of_edge_degrees_t;
     79typedef std::map< unsigned int, int> type_valence_map_t;
     80typedef std::map< edge_by_vertices_t , size_t> edge_index_t;
     81
     82static int powerset_edge_degree(
     83    list_of_edge_degrees_t &list_of_edge_degrees,
     84    degrees_t &current_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
     114static 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
     129static 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
     139static 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
     149struct 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
     159template <class graph_type>
     160static 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 &degrees
     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
     241template <typename graph_t>
     242BoostGraphCreator::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
    59278ActionState::ptr GraphChemicalSpaceEvaluatorAction::performCall() {
    60   // create boost::graph from graph6 string
     279  /// 1. create boost::graph from graph6 string
    61280  BoostGraphCreator BGC;
    62281  BGC.createFromGraph6String(params.graph_string.get());
     
    65284
    66285  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 index
     286  LOG(1, "INFO: We have " << boost::num_vertices(graph) << " nodes in the fragment graph.");
     287
     288  /// 2. associate type with a node index
    70289  Extractors::type_index_lookup_t type_index_lookup;
    71290  std::vector<unsigned int> elementnumbers;
    72291  elementnumbers.reserve(params.graph_elements.get().size());
     292  size_t i = 0;
    73293  for (std::vector<const element *>::const_iterator iter = params.graph_elements.get().begin();
    74294      iter != params.graph_elements.get().end(); ++iter) {
    75295    elementnumbers.push_back((*iter)->getAtomicNumber());
     296    LOG(3, "DEBUG: Adding [" << i << ", " << elementnumbers.back() << "] type to index lookup.");
    76297    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;
    83374  const size_t nodes_in_graph = boost::num_vertices(graph);
    84375  LOG(2, "DEBUG: There are " << nodes_in_graph << " nodes in the graph.");
     
    103394    LOG(3, "DEBUG: Nodes per level are " << nodes_per_level);
    104395
    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)
    106397    Extractors::nodes_t nodes;
    107398    // rootindex is always contained
     
    109400    Extractors::level_t level = 0;
    110401
    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);
    113405    LOG(2, "DEBUG: We have found " << set_of_nodes.size() << " unique induced, connected subgraphs.");
    114406  }
    115407
     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
    116414  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 &current_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 &current_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);
    135490  }
    136491
Note: See TracChangeset for help on using the changeset viewer.