Turi Create  4.0
sgraph_triple_apply.hpp
1 /* Copyright © 2017 Apple Inc. All rights reserved.
2  *
3  * Use of this source code is governed by a BSD-3-clause license that can
4  * be found in the LICENSE.txt file or at https://opensource.org/licenses/BSD-3-Clause
5  */
6 #ifndef TURI_SGRAPH_SGRAPH_TRIPLE_APPLY
7 #define TURI_SGRAPH_SGRAPH_TRIPLE_APPLY
8 
9 #include<core/data/flexible_type/flexible_type.hpp>
10 #include<core/storage/sgraph_data/sgraph.hpp>
11 #include<core/storage/sgraph_data/sgraph_compute_vertex_block.hpp>
12 
13 namespace turi {
14 
15 /**
16  * \ingroup sgraph_physical
17  * \addtogroup sgraph_compute SGraph Compute
18  * \{
19  */
20 
21 /**
22  * Graph Computation Functions
23  */
24 namespace sgraph_compute {
25 
26 typedef std::vector<flexible_type> vertex_data;
27 typedef std::vector<flexible_type> edge_data;
28 typedef sgraph::vertex_partition_address vertex_partition_address;
29 typedef sgraph::edge_partition_address edge_partition_address;
30 
31 /**
32  * Provide access to an edge scope (Vertex, Edge, Vertex);
33  * The scope object permits read, modify both vertex data
34  * and the edge data. See \ref triple_apply
35  */
36 class edge_scope {
37  public:
38  /// Provide vertex data access
39  vertex_data& source() { return *m_source; }
40 
41  const vertex_data& source() const { return *m_source; }
42 
43  vertex_data& target() { return *m_target; }
44 
45  const vertex_data& target() const { return *m_target; }
46 
47  /// Provide edge data access
48  edge_data& edge() { return *m_edge; }
49 
50  const edge_data& edge() const { return *m_edge; }
51 
52  /// Lock both source and target vertices
53  // The lock pointers can be null in which case the function has no effect.
54  void lock_vertices() {
55  if (m_lock_0 && m_lock_1) {
56  if (m_lock_0 == m_lock_1) {
57  m_lock_0->lock();
58  } else {
59  m_lock_0->lock();
60  m_lock_1->lock();
61  }
62  }
63  };
64 
65  /// Unlock both source and target vertices
66  void unlock_vertices() {
67  if (m_lock_0 && m_lock_1) {
68  if (m_lock_0 == m_lock_1) {
69  m_lock_0->unlock();
70  } else {
71  m_lock_0->unlock();
72  m_lock_1->unlock();
73  }
74  }
75  };
76 
77  /// Do not construct edge_scope directly. Used by triple_apply_impl.
78  edge_scope(vertex_data* source, vertex_data* target, edge_data* edge,
79  turi::mutex* lock_0=NULL,
80  turi::mutex* lock_1=NULL) :
81  m_source(source), m_target(target), m_edge(edge),
82  m_lock_0(lock_0), m_lock_1(lock_1) { }
83 
84  private:
85  vertex_data* m_source;
86  vertex_data* m_target;
87  edge_data* m_edge;
88  // On construction, the lock ordering is gauanteed: lock_0 < lock_1.
89  turi::mutex* m_lock_0;
90  turi::mutex* m_lock_1;
91 };
92 
93 typedef std::function<void(edge_scope&)> triple_apply_fn_type;
94 
95 typedef std::function<void(std::vector<edge_scope>&)> batch_triple_apply_fn_type;
96 
97 /**
98  * Apply a transform function on each edge and its associated source and target vertices in parallel.
99  * Each edge is visited once and in parallel. The modification to vertex data will be protected by lock.
100  *
101  * The effect of the function is equivalent to the following pesudo-code:
102  * \code
103  * parallel_for (edge in g) {
104  * lock(edge.source(), edge.target())
105  * apply_fn(edge.source().data(), edge.data(), edge.target().data());
106  * unlock(edge.source(), edge.target())
107  * }
108  * \endcode
109  *
110  * \param g The target graph to perform the transformation.
111  * \param apply_fn The user defined function that will be applied on each edge scope.
112  * \param mutated_vertex_fields A subset of vertex data columns that the apply_fn will modify.
113  * \param mutated_edge_fields A subset of edge data columns that the apply_fn will modify.
114  * \param requires_vertex_id Set to false for optimization when vertex id is not required
115  * for triple_apply computation.
116  *
117  * The behavior is undefined when mutated_vertex_fields, and mutated_edge_fields are
118  * inconsistent with the apply_fn function.
119  */
120 void triple_apply(sgraph& g,
121  triple_apply_fn_type apply_fn,
122  const std::vector<std::string>& mutated_vertex_fields,
123  const std::vector<std::string>& mutated_edge_fields = {},
124  bool requires_vertex_id = true);
125 
126 
127 #ifdef TC_HAS_PYTHON
128 /**
129  * Overload. Uses python lambda function.
130  */
131 void triple_apply(sgraph& g, const std::string& lambda_str,
132  const std::vector<std::string>& mutated_vertex_fields,
133  const std::vector<std::string>& mutated_edge_fields = {});
134 
135 #endif
136 
137 
138 /**************************************************************************/
139 /* */
140 /* Internal. Test Only API */
141 /* */
142 /**************************************************************************/
143 
144 /**
145  * Overload. Take the apply function that processes a batch of edges at once.
146  * Used for testing the building block of lambda triple apply.
147  */
148 void triple_apply(sgraph& g,
149  batch_triple_apply_fn_type batch_apply_fn,
150  const std::vector<std::string>& mutated_vertex_fields,
151  const std::vector<std::string>& mutated_edge_fields = {});
152 
153 /**
154  * Mock the single triple apply using batch_triple_apply implementation.
155  * Used for testing only.
156  */
158  triple_apply_fn_type apply_fn,
159  const std::vector<std::string>& mutated_vertex_fields,
160  const std::vector<std::string>& mutated_edge_fields = {});
161 }
162 
163 /// \}
164 }
165 
166 #endif
edge_data & edge()
Provide edge data access.
void lock() const
Acquires a lock on the mutex.
Definition: mutex.hpp:64
void unlock_vertices()
Unlock both source and target vertices.
void unlock() const
Releases a lock on the mutex.
Definition: mutex.hpp:73
vertex_data & source()
Provide vertex data access.
void lock_vertices()
Lock both source and target vertices.
void triple_apply(sgraph &g, triple_apply_fn_type apply_fn, const std::vector< std::string > &mutated_vertex_fields, const std::vector< std::string > &mutated_edge_fields={}, bool requires_vertex_id=true)
edge_scope(vertex_data *source, vertex_data *target, edge_data *edge, turi::mutex *lock_0=NULL, turi::mutex *lock_1=NULL)
Do not construct edge_scope directly. Used by triple_apply_impl.
void batch_triple_apply_mock(sgraph &g, triple_apply_fn_type apply_fn, const std::vector< std::string > &mutated_vertex_fields, const std::vector< std::string > &mutated_edge_fields={})