Cyclops Tensor Framework
parallel arithmetic on multidimensional arrays
apsp.cxx
Go to the documentation of this file.
1 
8 #include <ctf.hpp>
9 #include <float.h>
10 using namespace CTF;
11 struct path {
12  int w, h;
13  path(int w_, int h_){ w=w_; h=h_; }
14  path(){ w=0; h=0;};
15 };
16 
17 namespace CTF {
18  template <>
19  inline void Set<path>::print(char const * a, FILE * fp) const {
20  fprintf(fp,"(%d %d)",((path*)a)[0].w,((path*)a)[0].h);
21  }
22 }
23  // calculate APSP on a graph of n nodes distributed on World (communicator) dw
24 int apsp(int n,
25  World & dw,
26  int niter=0){
27 
28  //tropical semiring, define additive identity to be INT_MAX/2 to prevent integer overflow
29  Semiring<int> s(INT_MAX/2,
30  [](int a, int b){ return std::min(a,b); },
31  MPI_MIN,
32  0,
33  [](int a, int b){ return a+b; });
34 
35  //random adjacency matrix
36  Matrix<int> A(n, n, dw, s);
37  srand(dw.rank);
38  A.fill_random(0, n*n);
39  //no loops
40  A["ii"] = 0;
41 
42  //distance matrix to compute
43  Matrix<int> D(n, n, dw, s);
44 
45  //initialize to adjacency graph
46  D["ij"] = A["ij"];
47 
48  for (int i=1; i<n; i=i<<1){
49  //all shortest paths of up 2i hops consist of one or two shortest paths up to i hops
50  D["ij"] += D["ik"]*D["kj"];
51  }
52 
53  //struct for path with w=path weight, h=#hops
54  MPI_Op opath;
55 
56  MPI_Op_create(
57  [](void * a, void * b, int * n, MPI_Datatype*){
58  for (int i=0; i<*n; i++){
59  if (((path*)a)[i].w <= ((path*)b)[i].w)
60  ((path*)b)[i] = ((path*)a)[i];
61  }
62  },
63  1, &opath);
64 
65  //tropical semiring with hops carried by winner of min
66  Semiring<path> p(path(INT_MAX/2,0),
67  [](path a, path b){ if (a.w<b.w || (a.w == b.w && a.h<b.h)) return a; else return b; },
68  opath,
69  path(0,0),
70  [](path a, path b){ return path(a.w+b.w, a.h+b.h); });
71 
72  //path matrix to contain distance matrix
73  Matrix<path> P(n, n, dw, p);
74 
75  Function<int,path> setw([](int w){ return path(w, 1); });
76  P["ij"] = setw(A["ij"]);
77 // P["ij"] = ((Function<int,path>)([](int w){ return path(w, 1); }))(A["ij"]);
78 
79  //sparse path matrix to contain all paths of exactly i hops
80  Matrix<path> Pi(n, n, SP, dw, p);
81 
82  for (int i=1; i<n; i=i<<1){
83  //let Pi be all paths in P consisting of exactly i hops
84  Pi["ij"] = P["ij"];
85  Pi.sparsify([=](path p){ return (p.h == i); });
86 
87  //all shortest paths of up to 2i hops either
88  // (1) are a shortest path of length up to i
89  // (2) consist of a shortest path of length up to i and a shortest path of length exactly i
90  P["ij"] += Pi["ik"]*P["kj"];
91  }
92 
93  //check correctness by subtracting the two computed shortest path matrices from one another and checking that no nonzeros are left
94  Transform<path,int> xtrw([](path p, int & w){ return w-=p.w; });
95 
96  xtrw(P["ij"], D["ij"]);
97 
98  Matrix<int> D2(D);
99 
100  D2.sparsify([](int w){ return w!=0; });
101 
102  int64_t loc_nnz;
103  Pair<int> * prs;
104  D2.get_local_pairs(&loc_nnz, &prs, true);
105 
106  int pass = (loc_nnz == 0);
107 
108  if (dw.rank == 0){
109  MPI_Reduce(MPI_IN_PLACE, &pass, 1, MPI_INT, MPI_MIN, 0, MPI_COMM_WORLD);
110  if (pass)
111  printf("{ APSP by path doubling } passed \n");
112  else
113  printf("{ APSP by path doubling } failed \n");
114  } else
115  MPI_Reduce(&pass, MPI_IN_PLACE, 1, MPI_INT, MPI_MIN, 0, MPI_COMM_WORLD);
116  delete [] prs;
117 #ifndef TEST_SUITE
118  if (dw.rank == 0){
119  printf("Starting %d benchmarking iterations of dense APSP-PD...\n", niter);
120  }
121  double min_time = DBL_MAX;
122  double max_time = 0.0;
123  double tot_time = 0.0;
124  double times[niter];
125  Timer_epoch dapsp("dense APSP-PD");
126  dapsp.begin();
127  for (int i=0; i<niter; i++){
128  D["ij"] = A["ij"];
129  double start_time = MPI_Wtime();
130  for (int j=1; j<n; j=j<<1){
131  D["ij"] += D["ik"]*D["kj"];
132  }
133  double end_time = MPI_Wtime();
134  double iter_time = end_time-start_time;
135  times[i] = iter_time;
136  tot_time += iter_time;
137  if (iter_time < min_time) min_time = iter_time;
138  if (iter_time > max_time) max_time = iter_time;
139  }
140  dapsp.end();
141 
142  if (dw.rank == 0){
143  printf("Completed %d benchmarking iterations of dense APSP-PD (n=%d).\n", niter, n);
144  printf("All iterations times: ");
145  for (int i=0; i<niter; i++){
146  printf("%lf ", times[i]);
147  }
148  printf("\n");
149  std::sort(times,times+niter);
150  printf("Dense APSP (n=%d) Min time=%lf, Avg time = %lf, Med time = %lf, Max time = %lf\n",n,min_time,tot_time/niter, times[niter/2], max_time);
151  }
152  if (dw.rank == 0){
153  printf("Starting %d benchmarking iterations of sparse APSP-PD...\n", niter);
154  }
155  min_time = DBL_MAX;
156  max_time = 0.0;
157  tot_time = 0.0;
158  Timer_epoch sapsp("sparse APSP-PD");
159  sapsp.begin();
160  for (int i=0; i<niter; i++){
161  //P["ij"] = setw(A["ij"]);
162  P["ij"] = ((Function<int,path>)([](int w){ return path(w, 1); }))(A["ij"]);
163  double start_time = MPI_Wtime();
164  for (int j=1; j<n; j=j<<1){
165  Pi["ij"] = P["ij"];
166  Pi.sparsify([=](path p){ return (p.h == j); });
167  P["ij"] += Pi["ik"]*P["kj"];
168  }
169  double end_time = MPI_Wtime();
170  double iter_time = end_time-start_time;
171  times[i] = iter_time;
172  tot_time += iter_time;
173  if (iter_time < min_time) min_time = iter_time;
174  if (iter_time > max_time) max_time = iter_time;
175  }
176  sapsp.end();
177 
178  if (dw.rank == 0){
179  printf("Completed %d benchmarking iterations of sparse APSP-PD (n=%d).\n", niter, n);
180  printf("All iterations times: ");
181  for (int i=0; i<niter; i++){
182  printf("%lf ", times[i]);
183  }
184  printf("\n");
185  std::sort(times,times+niter);
186  printf("Sparse APSP (n=%d): Min time=%lf, Avg time = %lf, Med time = %lf, Max time = %lf\n",n,min_time,tot_time/niter, times[niter/2], max_time);
187  }
188 
189 #endif
190  return pass;
191 }
192 
193 
194 #ifndef TEST_SUITE
195 char* getCmdOption(char ** begin,
196  char ** end,
197  const std::string & option){
198  char ** itr = std::find(begin, end, option);
199  if (itr != end && ++itr != end){
200  return *itr;
201  }
202  return 0;
203 }
204 
205 
206 int main(int argc, char ** argv){
207  int rank, np, n, pass, niter;
208  int const in_num = argc;
209  char ** input_str = argv;
210 
211  MPI_Init(&argc, &argv);
212  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
213  MPI_Comm_size(MPI_COMM_WORLD, &np);
214 
215  if (getCmdOption(input_str, input_str+in_num, "-n")){
216  n = atoi(getCmdOption(input_str, input_str+in_num, "-n"));
217  if (n < 0) n = 7;
218  } else n = 7;
219 
220  if (getCmdOption(input_str, input_str+in_num, "-niter")){
221  niter = atof(getCmdOption(input_str, input_str+in_num, "-niter"));
222  if (niter < 0) niter = 10;
223  } else niter = 10;
224 
225  {
226  World dw(argc, argv);
227 
228  if (rank == 0){
229  printf("Computing APSP of dense graph with %d nodes using dense and sparse path doubling\n",n);
230  }
231  pass = apsp(n, dw, niter);
232  assert(pass);
233  }
234 
235  MPI_Finalize();
236  return 0;
237 }
243 #endif
Matrix class which encapsulates a 2D tensor.
Definition: matrix.h:18
int h
Definition: apsp.cxx:12
void get_local_pairs(int64_t *npair, Pair< dtype > **pairs, bool nonzeros_only=false, bool unpack_sym=false) const
gives the global indices and values associated with the local data
Definition: tensor.cxx:201
def rank(self)
Definition: core.pyx:312
Definition: common.h:37
int w
Definition: apsp.cxx:12
Semiring is a Monoid with an addition multiplicaton function addition must have an identity and be as...
Definition: semiring.h:359
an instance of the CTF library (world) on a MPI communicator
Definition: world.h:19
string
Definition: core.pyx:456
index-value pair used for tensor data input
Definition: tensor.h:28
int main(int argc, char **argv)
Definition: apsp.cxx:206
char * getCmdOption(char **begin, char **end, const std::string &option)
Definition: apsp.cxx:195
int rank
rank of local processor
Definition: world.h:24
void print(char const *a, FILE *fp=stdout) const
prints the value
Definition: set.h:386
void sparsify()
reduce tensor to sparse format, storing only nonzero data, or data above a specified threshold...
Definition: tensor.cxx:449
epoch during which to measure timers
Definition: timer.h:69
path(int w_, int h_)
Definition: apsp.cxx:13
path()
Definition: apsp.cxx:14
Definition: apsp.cxx:11
Definition: apsp.cxx:17
int apsp(int n, World &dw, int niter=0)
Definition: apsp.cxx:24
def np(self)
Definition: core.pyx:315