28 Şubat 2018 Çarşamba

msm state_machine Sınıfı

Giriş
Şu satırı dahil ederiz.
#include <boost/msm/back/state_machine.hpp>
Constructor
Template'ın ilk parametresi kendi state_machine_def sınıfından kalıtan sınıfımdır.
Örnek
msm::back::state_machine<my_fsm> my;
Örnek
Şöyle yaparız.
struct FSMDef : boost::msm::front::state_machine_def<FSMDef> {
  ...
}

using FSM = boost::msm::back::state_machine<FSMDef>;
FSM fsm;
Örnek
Şöyle yaparız.
namespace {

  class Shelf_Hooking;

  typedef msmb::state_machine<Shelf_Hooking, msmb::mpl_graph_fsm_check> SM_;

  struct Event {};

  class Shelf_Hooking : public msmf::state_machine_def<Shelf_Hooking> {
    ...

  }; /* End of State Machine class */

  /***************************************************************/
  /* Back-end */
  class state_machine_impl {
    std::unique_ptr<SM_> state_machine;

    public:
      state_machine_impl() : state_machine(new SM_()) {}

      ~state_machine_impl() {}

      void runSM() {
        state_machine->start();
        state_machine->process_event(Event());
      } /* End of runSM() */

  }; /* End of class state_machine_impl */

} /* End of namespace */

int main() {
  std::unique_ptr<state_machine_impl> Sm_ = std::unique_ptr<state_machine_impl>
    (new state_machine_impl());

  Sm_->runSM();
}
process_event metodu
Elimizde şöyle event'ler olsun.
struct Event1 {};
struct Event2 {};
Şöyle yaparız.
my.process_event(Event1());
start metodu
İlk state'e giriş yapar. process_event() metodundan önce çağrılır. Şöyle yaparız
my.start(); 

graph vertices metodu

Giriş
Tüm vertex'leri dolaşmamızı sağlayan bir iterator çifti döner. first iterator ilk vertex'e second iterator ise son vertex'e işaret eder.

Bu metod ile edges metodu kardeştir.
BGL_FORALL_VERTICES macrosu ile aynıdır.

Bu metod vertex_iterator tipinden iterator döner. İki iterator nesnesini dolaşmak için boost::make_iterator_range() kullanılabilir.

vertices - graph
Örnek
Elimizde vector tabanlı bir graph olsun
struct VertexProps { int id; default_color_type color; };

using Graph = adjacency_list<vecS, vecS, directedS, VertexProps>;

Graph g = ...;
Şöyle yaparız.
for (auto vd : boost::make_iterator_range(vertices(g))) {
    std::cout << "Vertex descriptor #" << vd 
         << " degree:" << degree(vd, g)
         << " id:"     << g[vd].id
         << " color:"  << g[vd].color
         << "\n";
}
Örnek
Her graph nesnesinin vertex'i anlamlı bir sayı vermeyebilir. std::vector tabanlı graph'larda sayıyı okuması kolaydır. Şöyle yaparız.
typedef boost::adjacency_list<> Graph;
typedef Graph::vertex_iterator Vit;
Graph g(10);

add_edge(2,5,g);
add_edge(5,3,g);
add_edge(3,8,g);

Vit begin, end;
boost::tie(begin, end) = vertices(g);

for (Vit it = begin; it != end; ++it) {
  unsigned edges = out_degree(*it, g);
  if (edges)
    std::cout << "vertex #" << *it << " has " << edges << " outgoing edge(s)\n";
  }
}
Çıktı olarak şunu alırız.
vertex #2 has 1 outgoing edge(s)
vertex #3 has 1 outgoing edge(s)
vertex #5 has 1 outgoing edge(s)
Eğer graph std::set tabanlı ise çıktıyı okumak zordur. edge eklemek için std::set'i std::vector'e çevirerek kullanırız. Şöyle yaparız.
typedef boost::adjacency_list<boost::setS, boost::listS/*, boost::undirectedS*/> Graph;
typedef Graph::vertex_iterator Vit;
Graph g(10);

Vit begin, end;
boost::tie(begin, end) = vertices(g);

{
  std::vector<Graph::vertex_descriptor> vindex(begin, end);
  add_edge(vindex[2], vindex[5], g);
  add_edge(vindex[5], vindex[3], g);
  add_edge(vindex[3], vindex[8], g);
}

for (Vit it = begin; it != end; ++it) {
  unsigned edges = out_degree(*it, g);
  if (edges)
    std::cout << "vertex #" << *it << " has " << edges << " outgoing edge(s)\n";
}
Çıktı olarak şunu alırız.
vertex #0x994d00 has 1 outgoing edge(s)
vertex #0x994d70 has 1 outgoing edge(s)
vertex #0x994e50 has 1 outgoing edge(s)
Bu durumda vertex'lere property ekleriz ve yine aynı şekilde edge eklemek için std::set'i std::vector'e çevirerek kullanırız.
struct VertexProperties {
    std::string name;
    VertexProperties(std::string name) : name(name) {}
};

typedef boost::adjacency_list<boost::setS, boost::listS, boost::directedS,
  VertexProperties> Graph;
typedef Graph::vertex_iterator Vit;
Graph g;

add_vertex(VertexProperties ("zero"), g);
add_vertex(VertexProperties ("one"), g);
add_vertex(VertexProperties ("two"), g);
add_vertex(VertexProperties ("three"), g);
add_vertex(VertexProperties ("four"), g);
add_vertex(VertexProperties ("five"), g);
add_vertex(VertexProperties ("six"), g);
add_vertex(VertexProperties ("seven"), g);
add_vertex(VertexProperties ("eight"), g);
add_vertex(VertexProperties ("nine"), g);

Vit begin, end;
boost::tie(begin, end) = vertices(g);

{
  std::vector<Graph::vertex_descriptor> vindex(begin, end);

  add_edge(vindex[2], vindex[5], g);
  add_edge(vindex[5], vindex[3], g);
  add_edge(vindex[3], vindex[8], g);
}

for (Vit it = begin; it != end; ++it) {
  unsigned edges = out_degree(*it, g);
  if (edges)
    std::cout << "vertex '" << g[*it].name << "' has " << edges << " outgoing edge(s)\n";
  }
}
Çıktı olarak şunu alırız.
vertex 'two' has 1 outgoing edge(s)
vertex 'three' has 1 outgoing edge(s)
vertex 'five' has 1 outgoing edge(s)
Örnek
Şöyle yaparız.Burada graph.m_vertices ile dokümante edilmemiş bir alana erişiyoruz. Bu alan graph vecS olarak tanımlı ise vector tipendendir.
VertexIterator vi, vi_end;
for (boost::tie(vi, vi_end) = vertices(graph); vi != vi_end; ++vi){
  graph.m_vertices[*vi].m_out_edges.reserve(6);
}
Örnek
Elimizde şöyle bir graph olsun.
struct mytuple
{
  int e1;
  int e2;
  int s;

  bool operator==(const mytuple& a) const
  {
    return ((e1 == a.e1) && (e2 == a.e2) && (s == a.s));
  }
};

struct MyVertex {
  std::string comments;
  int field1;
  mytuple value;
  MyVertex(std::string comments = std::string()) : comments(comments) {}
};

struct MyEdge {
  std::string label;
  MyEdge(std::string label = std::string()) : label(label) {}
};


using MyTree = boost::adjacency_list<boost::vecS, boost::vecS,
 boost::bidirectionalS, MyVertex, MyEdge>;
using Vertex = boost::graph_traits<MyTree>::vertex_descriptor; // Define Vertex
using VertexItr = boost::graph_traits<MyTree>::vertex_iterator; //Vertex iterator
using Edge = std::pair<boost::graph_traits<MyTree>::edge_descriptor, bool>; //Edge
using EdgeItr = boost::graph_traits<MyTree>::edge_iterator; // Edge Iterator
Graph'ı dolduralım
MyTree mytree;

Vertex v1 = boost::add_vertex(mytree);
mytree[v1].value = {1, 1, 1};
mytree[v1].comments = "I am the one you seek";

Vertex v2 = boost::add_vertex(mytree);
mytree[v2].value = {2, 2, 2};

Vertex v3 = boost::add_vertex(mytree);
mytree[v3].value = {3, 3, 3};
Tüm vertex'leri dolaşarak eşitlik kontrolü yapmak için şöyle yaparız.
VertexItr findvertex(const MyTree& g, const mytuple& value){
  VertexItr vi, vi_end;
  for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) {
    if(g[*vi].value == value) return vi;
  }
  return vi_end;
}
Kullanmak için şöyle yaparız.
mytuple tuple = { 1,1,1};
const auto iter = findvertex(mytree, tuple);
const auto theEnd = boost::vertices(mytree).second;
Örnek - pair
Elimizde şöyle bir grap olsun
struct Vertex { int id; double data; };
struct Edge { float distance; };

typedef boost::adjacency_list<boost::listS, boost::vecS, boost::directedS,
  Vertex, Edge> Graph;
Vertex'lerin başını ve sonunu std::pair olarak almak için şöyle yaparız
// Iterate through the vertices and print them out
typedef boost::graph_traits<Graph>::vertex_iterator vertex_iter;
std::pair<vertex_iter, vertex_iter> vp;
for (vp = boost::vertices(g); vp.first != vp.second; vp.first++)
{
  std::cout << g[*(vp.first)].id << " " << g[*(vp.first)].data << std::endl;
}
Her vertex'i yazdırınca çıktı olarak şunu alırız.
1 1.1
2 2.2
3 3.3
4 4.4
Örnek
Tüm vertex ve onların tüm komşularını dolaşmak için şöyle yaparız.
Graph g = ...;
Graph::vertex_iterator vertexIt, vertexEnd;

tie(vertexIt, vertexEnd) = vertices(g);

for (; vertexIt != vertexEnd; ++vertexIt) 
{
  Graph::adjacency_iterator neighbourIt, neighbourEnd;

  tie(neighbourIt, neighbourEnd) = adjacent_vertices(*vertexIt, inputgraph);

  for (; neighbourIt != neighbourEnd; ++neighbourIt){
    ...
  }
}
Örnek
vertices() çağrısının döndürdüğü vertex_iterator ile adjacent_vertices() çağrısının döndürdüğü adjacency_iterator tipleri birbirlerinden farklıdır. Şu kod derlenmez.
Elimizde bir grap olsun ve onu dolduralım.
typedef adjacency_list<vecS, vecS, directedS> digraph;
typedef graph_traits<digraph>::vertex_iterator vertex_it;
typedef graph_traits<digraph>::adjacency_iterator adj_it;
graph_traits<digraph>::vertex_descriptor a, b, c;

digraph g;
a = add_vertex(g);
b = add_vertex(g);
c = add_vertex(g);
add_edge(a, b, g);
add_edge(b, c, g);
add_edge(c, a, g);
Daha sonra iki iterator'ü karıştırmaya çalışalım. Kod derlenmez.
vector<vertex_it> stack;

vertex_it v_beg,v_end;
tie(v_beg,v_end) = vertices(g);
stack.push_back(v_beg);

adj_it adj_beg,adj_end;
tie(adj_beg, adj_end) = adjacent_vertices(*v_beg, g);
for (; adj_beg != adj_end; adj_beg++)
  stack.push_back(adj_beg); //error here
Örnek
Tüm vertex'leri rastgele dolaşmak isteyelim. Önce vertex'lerin başlangıcını  saklarız.
std::pair<vertex_iter, vertex_iter> vp;
vp = vertices(g);
Daha sonra sayıları rastgele karıştırırız.
// initialize pseudo random number generator
std::srand(unsigned (std::time(0)));

// create offset vector
std::vector<int> myvector;
for (int i=0; i<3; ++i) {
  myvector.push_back(i);
}

// using myrandom to shuffle offset vector
std::random_shuffle(myvector.begin(), myvector.end(), myrandom);
Rastgele dolaşmak için şöyle yaparız.
vertex_iter dummy_iter;
// Looping on a shuffled vector, values should be 0..N-1
for (std::vector<int>::iterator it=myvector.begin(); it!=myvector.end(); ++it)
{
  dummy_iter = vp.first + *it;
  Vertex* v = *dummy_iter;
  ...
}