agd.Eikonal.HFM_CUDA.graph_reverse

 1# Copyright 2020 Jean-Marie Mirebeau, University Paris-Sud, CNRS, University Paris-Saclay
 2# Distributed WITHOUT ANY WARRANTY. Licensed under the Apache License, Version 2.0, see http://www.apache.org/licenses/LICENSE-2.0
 3
 4import numpy as np
 5import cupy as cp
 6import os
 7from . import cupy_module_helper
 8from .cupy_module_helper import SetModuleConstant
 9
10def graph_reverse(fwd,fwd_weight,
11	invalid_index=None,nrev=None,blockDim=1024):
12	"""
13	Inverses a weighted graph. 
14	- invalid_index : special value to be ignored in fwd (defaults to Int_Max)
15	- nrev : expected max number of neighbors in reversed graph
16	- irev_t
17	Output : 
18	 - rev, rev_weight. !! Warning : likely not contiguous arrays. !!
19	"""
20	fwd = cp.ascontiguousarray(fwd)
21	fwd_weight = cp.ascontiguousarray(fwd_weight)
22
23	nfwd = len(fwd)
24	shape = fwd.shape[1:]
25	size = np.prod(shape)
26
27	int_t = fwd.dtype.type
28	weight_t = fwd_weight.dtype.type
29
30	if invalid_index is None: invalid_index = np.iinfo(int_t).max
31	if nrev is None: nrev = 2*nfwd # Default guess, will be increased if needed
32	for dtype in (np.int8,np.int16,np.int32,np.int64):
33		if np.iinfo(dtype).max>=nrev:
34			irev_t=dtype
35			break
36	else: raise ValueError("Impossible nrev")
37
38	rev = cp.full( (nrev,)+shape, invalid_index, dtype=int_t)
39	rev_weight = cp.zeros( (nrev,)+shape, dtype=weight_t)
40	irev = cp.zeros( (nfwd,)+shape, dtype=irev_t)
41
42	traits = {
43		'Int':int_t,
44		'weightT':weight_t,
45		'irevT':irev_t,
46		'invalid':(invalid_index,int_t),
47		'invalid_macro':True,
48	}
49
50	source = cupy_module_helper.traits_header(traits,integral_max=True)
51	cuda_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),"cuda")
52	date_modified = cupy_module_helper.getmtime_max(cuda_path)
53
54	source += [
55	'#include "GraphReverse.h"',
56	f"// Date cuda code last modified : {date_modified}"]
57	cuoptions = ("-default-device", f"-I {cuda_path}") 
58
59	source="\n".join(source)
60	module = cupy_module_helper.GetModule(source,cuoptions)
61	SetModuleConstant(module,'size_tot',size,int_t)
62	SetModuleConstant(module,'nfwd',nfwd,int_t)
63	SetModuleConstant(module,'nrev',nrev,int_t)
64
65	cupy_kernel = module.get_function("GraphReverse")
66	gridDim = int(np.ceil(size/blockDim))
67
68	irev_mmax = 0
69	for i in range(nrev): # By construction, at least one reverse index is set each iter
70		irev_max = np.max(irev)
71		irev_mmax = max(irev_max,irev_mmax)
72
73		if irev_max==-1: return rev[:irev_mmax+1],rev_weight[:irev_mmax+1]
74		if irev_max==nrev: # Some vertices have large reverse multiplicities
75			return graph_reverse(fwd,fwd_weight,invalid_index,2*nrev,blockDim=blockDim)
76
77		cupy_kernel((gridDim,),(blockDim,),(fwd,rev,irev,fwd_weight,rev_weight))
def graph_reverse(fwd, fwd_weight, invalid_index=None, nrev=None, blockDim=1024):
11def graph_reverse(fwd,fwd_weight,
12	invalid_index=None,nrev=None,blockDim=1024):
13	"""
14	Inverses a weighted graph. 
15	- invalid_index : special value to be ignored in fwd (defaults to Int_Max)
16	- nrev : expected max number of neighbors in reversed graph
17	- irev_t
18	Output : 
19	 - rev, rev_weight. !! Warning : likely not contiguous arrays. !!
20	"""
21	fwd = cp.ascontiguousarray(fwd)
22	fwd_weight = cp.ascontiguousarray(fwd_weight)
23
24	nfwd = len(fwd)
25	shape = fwd.shape[1:]
26	size = np.prod(shape)
27
28	int_t = fwd.dtype.type
29	weight_t = fwd_weight.dtype.type
30
31	if invalid_index is None: invalid_index = np.iinfo(int_t).max
32	if nrev is None: nrev = 2*nfwd # Default guess, will be increased if needed
33	for dtype in (np.int8,np.int16,np.int32,np.int64):
34		if np.iinfo(dtype).max>=nrev:
35			irev_t=dtype
36			break
37	else: raise ValueError("Impossible nrev")
38
39	rev = cp.full( (nrev,)+shape, invalid_index, dtype=int_t)
40	rev_weight = cp.zeros( (nrev,)+shape, dtype=weight_t)
41	irev = cp.zeros( (nfwd,)+shape, dtype=irev_t)
42
43	traits = {
44		'Int':int_t,
45		'weightT':weight_t,
46		'irevT':irev_t,
47		'invalid':(invalid_index,int_t),
48		'invalid_macro':True,
49	}
50
51	source = cupy_module_helper.traits_header(traits,integral_max=True)
52	cuda_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),"cuda")
53	date_modified = cupy_module_helper.getmtime_max(cuda_path)
54
55	source += [
56	'#include "GraphReverse.h"',
57	f"// Date cuda code last modified : {date_modified}"]
58	cuoptions = ("-default-device", f"-I {cuda_path}") 
59
60	source="\n".join(source)
61	module = cupy_module_helper.GetModule(source,cuoptions)
62	SetModuleConstant(module,'size_tot',size,int_t)
63	SetModuleConstant(module,'nfwd',nfwd,int_t)
64	SetModuleConstant(module,'nrev',nrev,int_t)
65
66	cupy_kernel = module.get_function("GraphReverse")
67	gridDim = int(np.ceil(size/blockDim))
68
69	irev_mmax = 0
70	for i in range(nrev): # By construction, at least one reverse index is set each iter
71		irev_max = np.max(irev)
72		irev_mmax = max(irev_max,irev_mmax)
73
74		if irev_max==-1: return rev[:irev_mmax+1],rev_weight[:irev_mmax+1]
75		if irev_max==nrev: # Some vertices have large reverse multiplicities
76			return graph_reverse(fwd,fwd_weight,invalid_index,2*nrev,blockDim=blockDim)
77
78		cupy_kernel((gridDim,),(blockDim,),(fwd,rev,irev,fwd_weight,rev_weight))

Inverses a weighted graph.

  • invalid_index : special value to be ignored in fwd (defaults to Int_Max)
  • nrev : expected max number of neighbors in reversed graph
  • irev_t Output :
    • rev, rev_weight. !! Warning : likely not contiguous arrays. !!