Zoltan2
Loading...
Searching...
No Matches
Zoltan2_AlgHybridPD2.hpp
Go to the documentation of this file.
1// @HEADER
2// *****************************************************************************
3// Zoltan2: A package of combinatorial algorithms for scientific computing
4//
5// Copyright 2012 NTESS and the Zoltan2 contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
10#ifndef _ZOLTAN2_PDISTANCE2_HPP_
11#define _ZOLTAN2_PDISTANCE2_HPP_
12
13#include <vector>
14#include <unordered_map>
15#include <iostream>
16#include <queue>
17#ifdef _WIN32
18#include <time.h>
19#else
20#include <sys/time.h>
21#endif
22
23#include "Zoltan2_Algorithm.hpp"
26#include "Zoltan2_Util.hpp"
27#include "Zoltan2_TPLTraits.hpp"
28#include "Zoltan2_AlltoAll.hpp"
29
30
31#include "Tpetra_Core.hpp"
32#include "Teuchos_RCP.hpp"
33#include "Tpetra_Import.hpp"
34#include "Tpetra_FEMultiVector.hpp"
35
36#include "Kokkos_Core.hpp"
37#include "KokkosSparse_CrsMatrix.hpp"
38#include "KokkosKernels_Handle.hpp"
39#include "KokkosKernels_IOUtils.hpp"
40#include "KokkosGraph_Distance2Color.hpp"
41#include "KokkosGraph_Distance2ColorHandle.hpp"
42
46
47
48namespace Zoltan2{
49
50template <typename Adapter>
51class AlgPartialDistance2 : public AlgTwoGhostLayer<Adapter> {
52
53 public:
54
55 using lno_t = typename Adapter::lno_t;
56 using gno_t = typename Adapter::gno_t;
57 using offset_t = typename Adapter::offset_t;
58 using scalar_t = typename Adapter::scalar_t;
59 using base_adapter_t = typename Adapter::base_adapter_t;
60 using map_t = Tpetra::Map<lno_t,gno_t>;
61 using femv_scalar_t = int;
62 using femv_t = Tpetra::FEMultiVector<femv_scalar_t, lno_t, gno_t>;
63 using device_type = typename femv_t::device_type;
64 using execution_space = typename device_type::execution_space;
65 using memory_space = typename device_type::memory_space;
66 using host_exec = typename femv_t::host_view_type::device_type::execution_space;
67 using host_mem = typename femv_t::host_view_type::device_type::memory_space;
68
69 private:
70 //serial and parallel local partial distance-2 coloring function
71 template<class ExecutionSpace, typename MemorySpace>
72 void localColoring(const size_t nVtx,
73 Kokkos::View<lno_t*, Kokkos::Device<ExecutionSpace, MemorySpace>> adjs_view,
74 Kokkos::View<offset_t*, Kokkos::Device<ExecutionSpace, MemorySpace>> offset_view,
75 Teuchos::RCP<femv_t> femv,
76 Kokkos::View<lno_t*, Kokkos::Device<ExecutionSpace, MemorySpace>> vertex_list,
77 size_t vertex_list_size = 0,
78 bool use_vertex_based_coloring = false){
79 using KernelHandle = KokkosKernels::Experimental::KokkosKernelsHandle
80 <offset_t, lno_t, lno_t, ExecutionSpace, MemorySpace, MemorySpace>;
81 KernelHandle kh;
82
83 //Instead of switching between vertex-based and net-based algorithms,
84 //we use only the net-based algorithm, as it is faster than its
85 //vertex-based counterpart.
86 kh.create_distance2_graph_coloring_handle(KokkosGraph::COLORING_D2_NB_BIT);
87
88 //vertex_list_size indicates whether we have provided a list of vertices to recolor
89 //NB_BIT does not currently make use of this.
90 if(vertex_list_size != 0){
91 kh.get_distance2_graph_coloring_handle()->set_vertex_list(vertex_list, vertex_list_size);
92 }
93
94 //the verbose argument should carry through the local coloring
95 kh.get_distance2_graph_coloring_handle()->set_verbose(this->verbose);
96
97 //set initial colors to be the colors from femv
98 auto femvColors = femv->template getLocalView<Kokkos::Device<ExecutionSpace,MemorySpace> >(Tpetra::Access::ReadWrite);
99 auto sv = subview(femvColors,Kokkos::ALL, 0);
100 kh.get_distance2_graph_coloring_handle()->set_vertex_colors(sv);
101
102 //call coloring
103 KokkosGraph::Experimental::bipartite_color_rows(&kh, nVtx, nVtx, offset_view, adjs_view, true);
104
105
106 //output total time
107 if(this->verbose){
108 std::cout<<"\nKokkosKernels Coloring: "
109 <<kh.get_distance2_graph_coloring_handle()->get_overall_coloring_time()
110 <<"\n";
111 }
112 }
113
114 //Entry point for parallel local coloring
115 virtual void colorInterior(const size_t nVtx,
116 Kokkos::View<lno_t*, device_type> adjs_view,
117 Kokkos::View<offset_t*, device_type> offset_view,
118 Teuchos::RCP<femv_t> femv,
119 Kokkos::View<lno_t*, device_type> vertex_list,
120 size_t vertex_list_size=0,
121 bool recolor=false){
122 this->localColoring<execution_space, memory_space>(nVtx,
123 adjs_view,
124 offset_view,
125 femv,
126 vertex_list,
127 vertex_list_size,
128 recolor);
129 }
130 //Entry point for serial local coloring
131 virtual void colorInterior_serial(const size_t nVtx,
132 typename Kokkos::View<lno_t*, device_type >::host_mirror_type adjs_view,
133 typename Kokkos::View<offset_t*,device_type >::host_mirror_type offset_view,
134 Teuchos::RCP<femv_t> femv,
135 typename Kokkos::View<lno_t*, device_type>::host_mirror_type vertex_list,
136 size_t vertex_list_size = 0,
137 bool recolor=false) {
138 this->localColoring<host_exec, host_mem>(nVtx,
139 adjs_view,
140 offset_view,
141 femv,
142 vertex_list,
143 vertex_list_size,
144 recolor);
145
146 }
147 public:
148 //serial and parallel partial distance-2 conflict detection function
149 template <class ExecutionSpace, typename MemorySpace>
150 void detectPD2Conflicts(const size_t n_local,
151 Kokkos::View<offset_t*, Kokkos::Device<ExecutionSpace, MemorySpace>> dist_offsets,
152 Kokkos::View<lno_t*, Kokkos::Device<ExecutionSpace, MemorySpace>> dist_adjs,
153 Kokkos::View<int*, Kokkos::Device<ExecutionSpace, MemorySpace>> femv_colors,
154 Kokkos::View<lno_t*, Kokkos::Device<ExecutionSpace, MemorySpace>> boundary_verts_view,
155 Kokkos::View<lno_t*,
156 Kokkos::Device<ExecutionSpace, MemorySpace> > verts_to_recolor_view,
157 Kokkos::View<int*,
158 Kokkos::Device<ExecutionSpace, MemorySpace>,
159 Kokkos::MemoryTraits<Kokkos::Atomic> > verts_to_recolor_size_atomic,
160 Kokkos::View<lno_t*,
161 Kokkos::Device<ExecutionSpace, MemorySpace> > verts_to_send_view,
162 Kokkos::View<size_t*,
163 Kokkos::Device<ExecutionSpace, MemorySpace>,
164 Kokkos::MemoryTraits<Kokkos::Atomic> > verts_to_send_size_atomic,
165 Kokkos::View<size_t*, Kokkos::Device<ExecutionSpace, MemorySpace>> recoloringSize,
166 Kokkos::View<int*, Kokkos::Device<ExecutionSpace, MemorySpace>> rand,
167 Kokkos::View<gno_t*, Kokkos::Device<ExecutionSpace, MemorySpace>> gid,
168 Kokkos::View<gno_t*, Kokkos::Device<ExecutionSpace, MemorySpace>> ghost_degrees,
169 bool recolor_degrees){
170
171 Kokkos::RangePolicy<ExecutionSpace> policy(0,boundary_verts_view.extent(0));
172 size_t local_recoloring_size;
173 Kokkos::parallel_reduce("PD2 conflict detection",policy, KOKKOS_LAMBDA(const uint64_t& i,size_t& recoloring_size){
174 //we only detect conflicts for vertices in the boundary
175 const size_t curr_lid = boundary_verts_view(i);
176 const int curr_color = femv_colors(curr_lid);
177 const size_t vid_d1_adj_begin = dist_offsets(curr_lid);
178 const size_t vid_d1_adj_end = dist_offsets(curr_lid+1);
179 const size_t curr_degree = vid_d1_adj_end - vid_d1_adj_begin;
180 for(size_t vid_d1_adj = vid_d1_adj_begin; vid_d1_adj < vid_d1_adj_end; vid_d1_adj++){
181 //we skip direct distance-1 conflicts, and only resolve distance-2 conflicts.
182 size_t vid_d1 = dist_adjs(vid_d1_adj);
183 size_t d2_adj_begin = dist_offsets(vid_d1);
184 size_t d2_adj_end = dist_offsets(vid_d1+1);
185
186 //If we find a conflict that uncolors curr_lid, we can safely stop detecting
187 //further conflicts starting at curr_lid. Because this is a nested loop,
188 //we'll use the found boolean to break twice and move to the next vertex.
189 bool found = false;
190 for(size_t vid_d2_adj = d2_adj_begin; vid_d2_adj < d2_adj_end; vid_d2_adj++){
191 const size_t vid_d2 = dist_adjs(vid_d2_adj);
192 size_t vid_d2_degree = 0;
193
194 //calculate the degree for degree-based recoloring
195 if(vid_d2 < n_local){
196 vid_d2_degree = dist_offsets(vid_d2+1) - dist_offsets(vid_d2);
197 } else {
198 vid_d2_degree = ghost_degrees(vid_d2-n_local);
199 }
200 //resolve conflict
201 if(curr_lid != vid_d2 && femv_colors(vid_d2) == curr_color){
202 if(curr_degree < vid_d2_degree && recolor_degrees){
203 found = true;
204 femv_colors(curr_lid) = 0;
205 recoloring_size++;
206 break;//---------------------------------------------------
207 } else if(vid_d2_degree < curr_degree && recolor_degrees){//|
208 femv_colors(vid_d2) = 0; //|
209 recoloring_size++; //|
210 } else if(rand(curr_lid) < rand(vid_d2)){ //|
211 found = true; //|
212 femv_colors(curr_lid) = 0; //|
213 recoloring_size++; //|
214 break;//--------------------------------------------------|
215 } else if(rand(vid_d2) < rand(curr_lid)){ //|
216 femv_colors(vid_d2) = 0; //|
217 recoloring_size++; //|
218 } else { //|
219 if(gid(curr_lid) >= gid(vid_d2)){ //|
220 found = true; //|
221 femv_colors(curr_lid) = 0; //|
222 recoloring_size++; //|
223 break;//------------------------------------------------|
224 } else { //|
225 femv_colors(vid_d2) = 0; //|
226 recoloring_size++;// v
227 }// If we uncolor the vertex whose neighbors we're
228 } // checking, each subsequent conflict check will
229 } // not do anything productive. We need this------
230 } // to completely move on to the next vertex. |
231 if(found) break;//<--------------------------------------------------
232 }
233 },local_recoloring_size);
234 Kokkos::deep_copy(recoloringSize, local_recoloring_size);
235 Kokkos::fence();
236 //update the verts_to_send and verts_to_recolor views
237 Kokkos::parallel_for("rebuild verts_to_send and verts_to_recolor",
238 Kokkos::RangePolicy<ExecutionSpace>(0,femv_colors.size()),
239 KOKKOS_LAMBDA(const uint64_t& i){
240 if(femv_colors(i) == 0){
241 if(i < n_local){
242 //we only send vertices owned by the current process
243 verts_to_send_view(verts_to_send_size_atomic(0)++) = i;
244 }
245 //we need to recolor all vertices for consistency.
246 verts_to_recolor_view(verts_to_recolor_size_atomic(0)++) = i;
247 }
248 });
249 Kokkos::fence();
250
251 }
252 //Entry point for parallel conflict detection
253 virtual void detectConflicts(const size_t n_local,
254 Kokkos::View<offset_t*, device_type > dist_offsets_dev,
255 Kokkos::View<lno_t*, device_type > dist_adjs_dev,
256 Kokkos::View<int*,device_type > femv_colors,
257 Kokkos::View<lno_t*, device_type > boundary_verts_view,
258 Kokkos::View<lno_t*,
259 device_type > verts_to_recolor_view,
260 Kokkos::View<int*,
262 Kokkos::MemoryTraits<Kokkos::Atomic>> verts_to_recolor_size_atomic,
263 Kokkos::View<lno_t*,
264 device_type > verts_to_send_view,
265 Kokkos::View<size_t*,
267 Kokkos::MemoryTraits<Kokkos::Atomic>> verts_to_send_size_atomic,
268 Kokkos::View<size_t*, device_type> recoloringSize,
269 Kokkos::View<int*,
270 device_type> rand,
271 Kokkos::View<gno_t*,
272 device_type> gid,
273 Kokkos::View<gno_t*,
274 device_type> ghost_degrees,
275 bool recolor_degrees){
276
277 this->detectPD2Conflicts<execution_space, memory_space>(n_local,
278 dist_offsets_dev,
279 dist_adjs_dev,
280 femv_colors,
281 boundary_verts_view,
282 verts_to_recolor_view,
283 verts_to_recolor_size_atomic,
284 verts_to_send_view,
285 verts_to_send_size_atomic,
286 recoloringSize,
287 rand,
288 gid,
289 ghost_degrees,
290 recolor_degrees);
291 }
292 //Entry point for serial conflict detection
293 virtual void detectConflicts_serial(const size_t n_local,
294 typename Kokkos::View<offset_t*, device_type >::host_mirror_type dist_offsets_host,
295 typename Kokkos::View<lno_t*, device_type >::host_mirror_type dist_adjs_host,
296 typename Kokkos::View<int*,device_type >::host_mirror_type femv_colors,
297 typename Kokkos::View<lno_t*, device_type >::host_mirror_type boundary_verts_view,
298 typename Kokkos::View<lno_t*,device_type>::host_mirror_type verts_to_recolor,
299 typename Kokkos::View<int*,device_type>::host_mirror_type verts_to_recolor_size,
300 typename Kokkos::View<lno_t*,device_type>::host_mirror_type verts_to_send,
301 typename Kokkos::View<size_t*,device_type>::host_mirror_type verts_to_send_size,
302 typename Kokkos::View<size_t*, device_type>::host_mirror_type recoloringSize,
303 typename Kokkos::View<int*, device_type>::host_mirror_type rand,
304 typename Kokkos::View<gno_t*,device_type>::host_mirror_type gid,
305 typename Kokkos::View<gno_t*,device_type>::host_mirror_type ghost_degrees,
306 bool recolor_degrees) {
307
308 this->detectPD2Conflicts<host_exec, host_mem>(n_local,
309 dist_offsets_host,
310 dist_adjs_host,
311 femv_colors,
312 boundary_verts_view,
313 verts_to_recolor,
314 verts_to_recolor_size,
315 verts_to_send,
316 verts_to_send_size,
317 recoloringSize,
318 rand,
319 gid,
320 ghost_degrees,
321 recolor_degrees);
322 }
323 //Entry point for boundary construction
324 virtual void constructBoundary(const size_t n_local,
325 Kokkos::View<offset_t*, device_type> dist_offsets_dev,
326 Kokkos::View<lno_t*, device_type> dist_adjs_dev,
327 typename Kokkos::View<offset_t*, device_type>::host_mirror_type dist_offsets_host,
328 typename Kokkos::View<lno_t*, device_type>::host_mirror_type dist_adjs_host,
329 Kokkos::View<lno_t*, device_type>& boundary_verts,
330 Kokkos::View<lno_t*,
331 device_type > verts_to_send_view,
332 Kokkos::View<size_t*,
334 Kokkos::MemoryTraits<Kokkos::Atomic>> verts_to_send_size_atomic){
335 //count the number of boundary vertices to correctly allocate
336 //the boundary vertex view on device
337 gno_t boundary_size_temp = 0;
338 for(size_t i = 0; i < n_local; i++){
339 for(offset_t j = dist_offsets_host(i); j < dist_offsets_host(i+1); j++){
340 if((size_t)dist_adjs_host(j) >= n_local){
341 boundary_size_temp++;
342 break;
343 }
344 bool found = false;
345 for(offset_t k = dist_offsets_host(dist_adjs_host(j)); k < dist_offsets_host(dist_adjs_host(j)+1); k++){
346 if((size_t)dist_adjs_host(k) >= n_local){
347 boundary_size_temp++;
348 found = true;
349 break;
350 }
351 }
352 if(found) break;
353 }
354 }
355
356 //Initialize the boundary on host
357 boundary_verts = Kokkos::View<lno_t*, device_type>("boundary verts",boundary_size_temp);
358 typename Kokkos::View<lno_t*, device_type>::host_mirror_type boundary_verts_host = Kokkos::create_mirror_view(boundary_verts);
359
360 //reset the boundary size count to use as an index to construct the view
361 boundary_size_temp = 0;
362
363 for(size_t i = 0; i < n_local; i++){
364 for(offset_t j = dist_offsets_host(i); j < dist_offsets_host(i+1); j++){
365 if((size_t)dist_adjs_host(j) >= n_local){
366 boundary_verts_host(boundary_size_temp++) = i;
367 break;
368 }
369 bool found = false;
370 for(offset_t k = dist_offsets_host(dist_adjs_host(j)); k < dist_offsets_host(dist_adjs_host(j)+1); k++){
371 if((size_t)dist_adjs_host(k) >= n_local){
372 boundary_verts_host(boundary_size_temp++) = i;
373 found = true;
374 break;
375 }
376 }
377 if(found) break;
378 }
379 }
380 //copy boundary over to device views
381 Kokkos::deep_copy(boundary_verts, boundary_verts_host);
382
383 //initialize the verts_to_send views
384 Kokkos::parallel_for("init verts to send",
385 Kokkos::RangePolicy<execution_space, int>(0,n_local),
386 KOKKOS_LAMBDA(const int& i){
387 for(offset_t j = dist_offsets_dev(i); j < dist_offsets_dev(i+1); j++){
388 if((size_t)dist_adjs_dev(j) >= n_local){
389 verts_to_send_view(verts_to_send_size_atomic(0)++) = i;
390 break;
391 }
392 bool found = false;
393 for(offset_t k = dist_offsets_dev(dist_adjs_dev(j)); k < dist_offsets_dev(dist_adjs_dev(j)+1); k++){
394 if((size_t)dist_adjs_dev(k) >= n_local){
395 verts_to_send_view(verts_to_send_size_atomic(0)++) = i;
396 found = true;
397 break;
398 }
399 }
400 if(found) break;
401 }
402 });
403 Kokkos::fence();
404
405 }
406
407
408 public:
410 const RCP<const base_adapter_t> &adapter_,
411 const RCP<Teuchos::ParameterList> &pl_,
412 const RCP<Environment> &env_,
413 const RCP<const Teuchos::Comm<int> > &comm_)
414 : AlgTwoGhostLayer<Adapter>(adapter_,pl_,env_,comm_){}
415
416
417
418}; //end class
419
420
421
422}//end namespace Zoltan2
423
424#endif
AlltoAll communication methods.
Defines the ColoringSolution class.
Defines the GraphModel interface.
Traits class to handle conversions between gno_t/lno_t and TPL data types (e.g., ParMETIS's idx_t,...
A gathering of useful namespace methods.
typename Adapter::scalar_t scalar_t
void detectPD2Conflicts(const size_t n_local, Kokkos::View< offset_t *, Kokkos::Device< ExecutionSpace, MemorySpace > > dist_offsets, Kokkos::View< lno_t *, Kokkos::Device< ExecutionSpace, MemorySpace > > dist_adjs, Kokkos::View< int *, Kokkos::Device< ExecutionSpace, MemorySpace > > femv_colors, Kokkos::View< lno_t *, Kokkos::Device< ExecutionSpace, MemorySpace > > boundary_verts_view, Kokkos::View< lno_t *, Kokkos::Device< ExecutionSpace, MemorySpace > > verts_to_recolor_view, Kokkos::View< int *, Kokkos::Device< ExecutionSpace, MemorySpace >, Kokkos::MemoryTraits< Kokkos::Atomic > > verts_to_recolor_size_atomic, Kokkos::View< lno_t *, Kokkos::Device< ExecutionSpace, MemorySpace > > verts_to_send_view, Kokkos::View< size_t *, Kokkos::Device< ExecutionSpace, MemorySpace >, Kokkos::MemoryTraits< Kokkos::Atomic > > verts_to_send_size_atomic, Kokkos::View< size_t *, Kokkos::Device< ExecutionSpace, MemorySpace > > recoloringSize, Kokkos::View< int *, Kokkos::Device< ExecutionSpace, MemorySpace > > rand, Kokkos::View< gno_t *, Kokkos::Device< ExecutionSpace, MemorySpace > > gid, Kokkos::View< gno_t *, Kokkos::Device< ExecutionSpace, MemorySpace > > ghost_degrees, bool recolor_degrees)
typename device_type::memory_space memory_space
AlgPartialDistance2(const RCP< const base_adapter_t > &adapter_, const RCP< Teuchos::ParameterList > &pl_, const RCP< Environment > &env_, const RCP< const Teuchos::Comm< int > > &comm_)
Tpetra::FEMultiVector< femv_scalar_t, lno_t, gno_t > femv_t
typename device_type::execution_space execution_space
typename femv_t::host_view_type::device_type::execution_space host_exec
virtual void detectConflicts_serial(const size_t n_local, typename Kokkos::View< offset_t *, device_type >::host_mirror_type dist_offsets_host, typename Kokkos::View< lno_t *, device_type >::host_mirror_type dist_adjs_host, typename Kokkos::View< int *, device_type >::host_mirror_type femv_colors, typename Kokkos::View< lno_t *, device_type >::host_mirror_type boundary_verts_view, typename Kokkos::View< lno_t *, device_type >::host_mirror_type verts_to_recolor, typename Kokkos::View< int *, device_type >::host_mirror_type verts_to_recolor_size, typename Kokkos::View< lno_t *, device_type >::host_mirror_type verts_to_send, typename Kokkos::View< size_t *, device_type >::host_mirror_type verts_to_send_size, typename Kokkos::View< size_t *, device_type >::host_mirror_type recoloringSize, typename Kokkos::View< int *, device_type >::host_mirror_type rand, typename Kokkos::View< gno_t *, device_type >::host_mirror_type gid, typename Kokkos::View< gno_t *, device_type >::host_mirror_type ghost_degrees, bool recolor_degrees)
typename femv_t::device_type device_type
typename femv_t::host_view_type::device_type::memory_space host_mem
virtual void constructBoundary(const size_t n_local, Kokkos::View< offset_t *, device_type > dist_offsets_dev, Kokkos::View< lno_t *, device_type > dist_adjs_dev, typename Kokkos::View< offset_t *, device_type >::host_mirror_type dist_offsets_host, typename Kokkos::View< lno_t *, device_type >::host_mirror_type dist_adjs_host, Kokkos::View< lno_t *, device_type > &boundary_verts, Kokkos::View< lno_t *, device_type > verts_to_send_view, Kokkos::View< size_t *, device_type, Kokkos::MemoryTraits< Kokkos::Atomic > > verts_to_send_size_atomic)
Tpetra::Map< lno_t, gno_t > map_t
typename Adapter::offset_t offset_t
virtual void detectConflicts(const size_t n_local, Kokkos::View< offset_t *, device_type > dist_offsets_dev, Kokkos::View< lno_t *, device_type > dist_adjs_dev, Kokkos::View< int *, device_type > femv_colors, Kokkos::View< lno_t *, device_type > boundary_verts_view, Kokkos::View< lno_t *, device_type > verts_to_recolor_view, Kokkos::View< int *, device_type, Kokkos::MemoryTraits< Kokkos::Atomic > > verts_to_recolor_size_atomic, Kokkos::View< lno_t *, device_type > verts_to_send_view, Kokkos::View< size_t *, device_type, Kokkos::MemoryTraits< Kokkos::Atomic > > verts_to_send_size_atomic, Kokkos::View< size_t *, device_type > recoloringSize, Kokkos::View< int *, device_type > rand, Kokkos::View< gno_t *, device_type > gid, Kokkos::View< gno_t *, device_type > ghost_degrees, bool recolor_degrees)
typename Adapter::base_adapter_t base_adapter_t
Created by mbenlioglu on Aug 31, 2020.