⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gb_rand.w

📁 模拟器提供了一个简单易用的平台
💻 W
📖 第 1 页 / 共 2 页
字号:
% This file is part of the Stanford GraphBase (c) Stanford University 1993@i boilerplate.w %<< legal stuff: PLEASE READ IT BEFORE MAKING ANY CHANGES!@i gb_types.w\def\title{GB\_\,RAND}\prerequisite{GB\_\,GRAPH}@*Random graphs. This GraphBase module provides two externalsubroutines called |random_graph| and |random_bigraph|, which generategraphs in which the arcs or edges have been selected ``at random.''  Athird subroutine, |random_lengths|, randomizes the lengths of the arcsof a given graph.  The performance of algorithms on such graphs canfruitfully be compared to their performance on the nonrandom graphsgenerated by other GraphBase routines.Before reading this code, the reader should be familiar with the basicdata structures and conventions described in {\sc GB\_\,GRAPH}. Theroutines in {\sc GB\_\,GRAPH} are loaded together with all GraphBaseapplications, and the programs below are typical illustrations of howto use them.@d random_graph r_graph /* abbreviations for Procrustean external linkage */@d random_bigraph r_bigraph@d random_lengths r_lengths@(gb_rand.h@>=#define random_graph r_graph /* users of {\sc GB\_\,RAND} should include this header info */#define random_bigraph r_bigraph#define random_lengths r_lengthsextern Graph *random_graph();extern Graph *random_bigraph();extern long random_lengths();@ Here is an overview of the file \.{gb\_rand.c}, the \CEE/ code for theroutines in question.@p#include "gb_graph.h" /* this header file teaches \CEE/ about GraphBase */#include "gb_flip.h" /* we will use the {\sc GB\_\,FLIP} routines for random numbers */@h@#@<Private declarations@>@;@<Internal functions@>@;@<External functions@>@ The procedure |random_graph(n,m,multi,self,directed,dist_from,dist_to,min_len,max_len,seed)| is designed to produce a pseudo-random graph with|n| vertices and |m| arcs or edges, using pseudo-random numbers thatdepend on |seed| in a system-independent fashion. The remaining parametersspecify a variety of options:$$\vcenter{\halign{#\hfil\cr|multi!=0| permits duplicate arcs;\cr|self!=0| permits self-loops (arcs from a vertex to itself);\cr|directed!=0| makes the graph directed; otherwise each arc becomes an undirected edge;\cr|dist_from| and |dist_to| specify probability distributions on the arcs;\cr|min_len| and |max_len| bound the arc lengths, which will be uniformlydistributed between these limits.\cr}}$$If |dist_from| or |dist_to| are |NULL|, the probability distribution isuniform over vertices; otherwise the \\{dist} parameter points to an array of|n| nonnegative integers that sum to $2^{30}$, specifying the respectiveprobabilities (times $2^{30}$) that each given vertex will appear as thesource or destination of the random arcs.A special option |multi=-1| is provided. This acts exactly like|multi=1|, except that arcs are not physically duplicated in computermemory---they are replaced by a single arc whose length is the minimumof all arcs having a common source and destination.The vertices are named simply |"0"|, |"1"|, |"2"|, and so on.Warning: Users need to initialize the random number generator beforecalling |random_graph|, or any other GraphBase procedure thatconsumes random numbers. (See {\sc GB\_\,FLIP}.)@ Examples: |random_graph(1000,5000,0,0,0,NULL,NULL,1,1,0)| creates a randomundirected graph with 1000 vertices and 5000 edges (hence 10000 arcs) oflength~1, havingno duplicate edges or self-loops. There are ${1000\choose2}=499500$ possibleundirected edges on 1000 vertices; hence there are exactly $499500\choose5000$possible graphs meeting these specifications. Every such graph would beequally likely, if |random_graph| had access to an ideal source ofrandom numbers. The GraphBase programs are designed to besystem-independent, so that identical graphs will be obtained byeverybody who asks for |random_graph(1000,5000,0,0,0,NULL,NULL,1,1,0)|.Equivalent experiments on algorithms for graph manipulation can thereforebe performed by researchers in different parts of the world.The subroutine call |random_graph(1000,5000,0,0,0,NULL,NULL,1,1,s)|will produce different graphs when the random seed |s| varies;however, the graph for any particular value of~|s| will be the same onall computers. The seed value can be any integer in the range $0\le s<2^{31}$.To get a random directed graph, allowing self-loops and repeated arcs,and with a uniform distribution on vertices, ask for$$\hbox{|random_graph(n,m,1,1,1,NULL,NULL,1,1,s)|}.$$Each of the $m$ arcs of that digraph has probability $1/n^2$ of being from$u$ to $v$, for all $u$ and~$v$. If self-loops are disallowed (bychanging `|1,1,1|' to `|1,0,1|'), each arc has probability$1/(n^2-n)$ of being from $u$ to $v$, for all $u\ne v$.To get a random directed graph in which vertex $k$ is twice as likelyas vertex $k+1$ to be the source of an arc but only half as likely tobe the destination of an arc, for all~$k$, try$$\hbox{|random_graph(31,m,1,1,1,d0,d1,0,255,s)|}$$where the arrays |d0| and |d1| have the static declarations$$\vbox{\hbox{|long d0[31]={0x20000000,0x10000000,@[@t\dots@>@],4,2,1,1};|}\hbox{|long d1[31]={1,1,2,4,@[@t\dots@>@],0x10000000,0x20000000};|}}$$then about 1/4 of the arcs will run from 0 to 30, while arcsfrom 30 to 0 will be extremely rare (occurring with probability $2^{-60}$).Incidentally, the arc lengths in this example will be random bytes,uniformly distributed between 0 and 255, because |min_len=0| and|max_len=255|.If we forbid repeated arcs in this example, by setting |multi=0|, theeffect is to discard all arcs having the same source and destinationas a previous arc, regardless of length. In such a case |m|~had better notbe too large, because the algorithm will keep going until it has found|m| distinct arcs, and many arcs are quite rare indeed; they willprobably not be found until hundreds of centuries have elapsed.A random bipartite graph can also be obtained as a special case of|random_graph|; this case is explained below.Semantics:If |multi=directed=0| and |self!=0|, we have an undirected graph withoutduplicate edges but with self-loops permitted. A self-loop then consists oftwo identical self-arcs, in spite of the fact that |multi=0|.@ If the |random_graph| routine encounters a problem, it returns|NULL|, after putting a code number into the external variable|panic_code|. This code number identifies the type of failure.Otherwise |random_graph| returns a pointer to the newly created graphand leaves |panic_code| unchanged. The |gb_trouble_code| will becleared to zero after |random_graph| has acted.@d panic(c) @+{@+panic_code=c;@+gb_trouble_code=0;@+return NULL;@+}@<External f...@>=Graph *random_graph(n,m,multi,self,directed,dist_from,dist_to,min_len,max_len,                       seed)  unsigned long n; /* number of vertices desired */  unsigned long m; /* number of arcs or edges desired */  long multi; /* allow duplicate arcs? */  long self; /* allow self loops? */  long directed; /* directed graph? */  long *dist_from; /* distribution of arc sources */  long *dist_to; /* distribution of arc destinations */  long min_len,max_len; /* bounds on random lengths */  long seed; /* random number seed */{@+@<Local variables@>@;@#  if (n==0) panic(bad_specs); /* we gotta have a vertex */  if (min_len>max_len) panic(very_bad_specs); /* what are you trying to do? */  if (((unsigned long)(max_len))-((unsigned long)(min_len))>=      ((unsigned long)0x80000000)) panic(bad_specs+1); /* too much range */  @<Check the distribution parameters@>;  gb_init_rand(seed);  @<Create a graph with |n| vertices and no arcs@>;  @<Build tables for nonuniform distributions, if needed@>;  for (mm=m; mm; mm--)    @<Add a random arc or a random edge@>;trouble: if (gb_trouble_code) {    gb_recycle(new_graph);    panic(alloc_fault); /* oops, we ran out of memory somewhere back there */  }  gb_free(new_graph->aux_data);  return new_graph;}@ @<Local var...@>=Graph *new_graph; /* the graph constructed by |random_graph| */long mm; /* the number of arcs or edges we still need to generate */register long k; /* vertex being processed */@ @d dist_code(x) (x? "dist": "0")@<Create a graph with |n| vertices and no arcs@>=new_graph=gb_new_graph(n);if (new_graph==NULL)  panic(no_room); /* out of memory before we're even started */for (k=0; k<n; k++) {  sprintf(name_buffer,"%ld",k);  (new_graph->vertices+k)->name=gb_save_string(name_buffer);}sprintf(new_graph->id,"random_graph(%lu,%lu,%d,%d,%d,%s,%s,%ld,%ld,%ld)",@| n,m,multi>0?1:multi<0?-1:0,self?1:0,directed?1:0,@| dist_code(dist_from),dist_code(dist_to),min_len,max_len,seed);@ @<Private d...@>=static char name_buffer[]="9999999999";@ @d rand_len (min_len==max_len?min_len:min_len+gb_unif_rand(max_len-min_len+1))@<Add a random arc or a random edge@>={@+register Vertex *u,*v;repeat:  if (dist_from)    @<Generate a random vertex |u| according to |dist_from|@>@;  else u=new_graph->vertices+gb_unif_rand(n);  if (dist_to)    @<Generate a random vertex |v| according to |dist_to|@>@;  else v=new_graph->vertices+gb_unif_rand(n);  if (u==v && !self) goto repeat;  if (multi<=0)    @<Search for duplicate arcs or edges; |goto repeat| or |done| if found@>;  if (directed) gb_new_arc(u,v,rand_len);  else gb_new_edge(u,v,rand_len);done:;}@ When we decrease the length of an existing edge, we use the fact thatits two arcs are adjacent in memory. If |u==v| in this case, we encounterthe first of two mated arcs before seeing the second; hence the mate ofthe arc we find is in location |a+1| when |u<=v|, and in location|a-1| when |u>v|.We must exit to location |trouble| if memory has been exhausted;otherwise there is a danger of an infinite loop, with |dummy_arc->next=dummy_arc|.@<Search for duplicate arcs or edges; |goto repeat| or |done| if found@>=if (gb_trouble_code) goto trouble;else {@+register Arc *a;  long len; /* length of new arc or edge being combined with previous */  for (a=u->arcs; a; a=a->next)    if (a->tip==v)      if (multi==0) goto repeat; /* reject a duplicate arc */      else { /* |multi<0| */        len=rand_len;        if (len<a->len) {          a->len=len;          if (!directed) {            if (u<=v) (a+1)->len=len;            else (a-1)->len=len;          }        }        goto done;      }}@* Nonuniform random number generation. The |random_graph| procedure iscomplete except for the parts that handle general distributions |dist_from|and |dist_to|. Before attempting to generate those distributions, we had bettercheck them to make sure that the specifications are well formed;otherwise disaster might ensue later. This part of the program is easy. @<Check the distribution parameters@>={@+register long acc; /* sum of probabilities */  register long *p; /* pointer to current probability of interest */  if (dist_from) {    for (acc=0,@,p=dist_from; p<dist_from+n; p++) {      if (*p<0) panic(invalid_operand);        /* |dist_from| contains a negative entry */      if (*p>0x40000000-acc) panic(invalid_operand+1);        /* probability too high */      acc+=*p;    }    if (acc!=0x40000000)      panic(invalid_operand+2); /* |dist_from| table doesn't sum to $2^{30}$ */  }  if (dist_to) {    for (acc=0,@,p=dist_to; p<dist_to+n; p++) {      if (*p<0) panic(invalid_operand+5);         /* |dist_to| contains a negative entry */      if (*p>0x40000000-acc) panic(invalid_operand+6);         /* probability too high */      acc+=*p;    }    if (acc!=0x40000000)      panic(invalid_operand+7); /* |dist_to| table doesn't sum to $2^{30}$ */  }}@ We generate nonuniform distributions by using Walker's alias@^Walker, Alistair J.@>method (see, for example, {\sl Seminumerical Algorithms}, second edition,exercise 3.4.1--7). Walker's method involves setting up ``magic'' tablesof length |nn|, where |nn| is the smallest power of~2 that is |>=n|.@f magic_entry int@<Local v...@>=long nn=1; /* this will be increased to $2^{\lceil\mskip1mu\lg n\rceil}$ */long kk=31; /* this will be decreased to $31-\lceil\mskip1mu\lg n\rceil$ */magic_entry *from_table, *to_table; /* alias tables */@ @<Build...@>={  if (dist_from) {    while (nn<n) nn+=nn, kk--;    from_table=walker(n,nn,dist_from,new_graph);  }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -