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

📄 gb_econ.w

📁 模拟器提供了一个简单易用的平台
💻 W
📖 第 1 页 / 共 2 页
字号:
strcpy((p+1)->title,"Users");@+node_index[MAX_N]=p+1;@ The remaining part of \.{econ.dat} is an $81\times80$ matrix in whichthe $k$th row contains the outputs of sector~$k$ to all sectors except\.{Users}. Each row consists of a blank line followed by 8 data lines;each data line contains 10 numbers separated by commas.Zeroes are represented by |""| instead of by |"0"|.For example, the data line $$\hbox{\tt8490,2182,42,467,,,,,,}$$ follows the initial blank line; it meansthat sector~1 output 8490 million dollars to itself, \$2182M tosector~2, \dots, \$0M to sector~10.@<Read and store the output...@>={@+register long s=0; /* row sum */  register long x; /* entry read from \.{econ.dat} */  if (gb_char()!='\n') panic(syntax_error+5);   /* blank line missing between rows */  gb_newline();  p=node_index[k];  for (j=1;j<MAX_N;j++) {    p->table[j]=x=gb_number(10);@+s+=x;    node_index[j]->total+=x;    if ((j%10)==0) {      if (gb_char()!='\n') panic(syntax_error+6);       /* out of synch in input file */      gb_newline();    }@+else if (gb_char()!=',') panic(syntax_error+7);     /* missing comma after entry */  }  p->table[MAX_N]=s; /* sum of |table[1]| through |table[80]| */}@* Growing a subtree.Once all the data appears in |node_block|, we want to extract from itand combine~it as specified by parameters |n|, |omit|, and |seed|.This amalgamation process effectively prunes the tree; it can also beregarded as a procedure that grows a subtree of the full economic tree.@<Determine the |n| sectors to use in the graph@>={@+long l=n+omit-2; /* the number of leaves in the desired subtree */  if (l==NORM_N) @<Choose all sectors@>@;  else if (seed) @<Grow a random subtree with |l| leaves@>@;  else @<Grow a subtree with |l| leaves by subdividing largest sectors first@>;}@ The chosen leaves of our subtree are identified by having their|tag| field set to~1.@<Choose all sectors@>=for (k=NORM_N;k;k--) node_index[k]->tag=1;@ To grow the |l|-leaf subtree when |seed=0|, we first pass over thetree bottom-up to compute the total input (and output) of each macro-sector;then we proceed from the top down to subdivide sectors in decreasingorder of their total input. This process provides a good introduction to thebottom-up and top-down tree methods we will be using in several otherparts of the program.The |special| node is used here for two purposes: It is the head of alinked list of unexplored nodes, sorted by decreasing order oftheir |total| fields; and it appears at the end of that list, because|special->total=0|.@<Grow a subtree with |l| leaves by subdividing largest sectors first@>={@+register node *special=node_index[MAX_N];     /* the \.{Users} node at the end of |node_block| */  for (p=node_index[ADJ_SEC]-1;p>=node_block;p--) /* bottom up */    if (p->rchild)      p->total=(p+1)->total+p->rchild->total;  special->link=node_block;@+node_block->link=special; /* start at the root */  k=1; /* |k| is the number of nodes we have tagged or put onto the list */  while (k<l) @<If the first node on the list is a leaf, delete it and tag it;                otherwise replace it by its two children@>;  for (p=special->link;p!=special;p=p->link)    p->tag=1; /* tag everything on the list */}@ @<If the first node on the list is a leaf,...@>={  p=special->link; /* remove |p|, the node with greatest |total| */  special->link=p->link;  if (p->rchild==0) p->tag=1; /* |p| is a leaf */  else {    pl=p+1;@+pr=p->rchild;    for (q=special;q->link->total>pl->total;q=q->link) ;    pl->link=q->link;@+q->link=pl; /* insert left child in its proper place */    for (q=special;q->link->total>pr->total;q=q->link) ;    pr->link=q->link;@+q->link=pr; /* insert right child in its proper place */    k++;  }}@ We can obtain a uniformly distributed |l|-leaf subtree of a given treeby choosing the root when |l=1| or by using the following idea when |l>1|:Suppose the given tree~$T$ has subtrees $T_0$ and $T_1$. Then it has$T(l)$ subtrees with |l|~leaves, where $T(l)=\sum_k T_0(k)T_1(l-k)$.We choose a random number $r$ between 0 and $T(l)-1$, and we find thesmallest $m$ such that $\sum_{k\le m}T_0(k)T_1(l-k)>r$. Then weproceed recursively tocompute a random $m$-leaf subtree of~$T_0$ and a random $(l-m)$-leafsubtree of~$T_1$.A difficulty arises when $T(l)$ is $2^{31}$ or more. But then we can replace$T_0(k)$ and $T_1(l-k)$ in the formulas above by $\lceil T_0(k)/d_0\rceil$and $\lceil T_1(k)/d_1\rceil$, respectively, where $d_0$ and $d_1$ arearbitrary constants; this yields smaller values$T(l)$ that define approximately the same distribution of~$k$.The program here computes the $T(l)$ values bottom-up, then grows arandom tree top-down. If node~|p| is not a leaf, its |table[0]| fieldwill be set to the number of leaves below it; and its |table[l]| fieldwill be set to $T(l)$, for |1<=l<=table[0]|.The data in \.{econ.dat} is sufficiently simple that most of the $T(l)$values are less than $2^{31}$. We need to scale themdown to avoid overflow only at the root node of the tree; thiscase is handled separately.We set the |tag| field of a node equal to the number of leaves to begrown in the subtree rooted at that node. This convention is consistentwith our previous stipulation that |tag=1| should characterize thenodes that are chosen to be vertices.@<Grow a random subtree with |l| leaves@>={  node_block->tag=l;  for (p=node_index[ADJ_SEC]-1;p>node_block;p--) /* bottom up, except root */    if (p->rchild) @<Compute the $T(l)$ values for subtree |p|@>;  for (p=node_block;p<node_index[ADJ_SEC];p++) /* top down, from root */    if (p->tag>1) {      l=p->tag;      pl=p+1;@+pr=p->rchild;      if (pl->rchild==NULL) {        pl->tag=1;@+pr->tag=l-1;      }@+else if (pr->rchild==NULL) {        pl->tag=l-1;@+pr->tag=1;      }@+else @<Stochastically determine the number of leaves to grow in                    each of |p|'s children@>;    }}@ Here we are essentially multiplying two generating functions.Suppose $f(z)=\sum_l T(l)z^l$; then we are computing $f_p(z)=z+f_{pl}(z)f_{pr}(z)$.@<Compute the $T(l)$ values for subtree |p|@>={  pl=p+1;@+pr=p->rchild;  p->table[1]=p->table[2]=1; /* $T(1)$ and $T(2)$ are always 1 */  if (pl->rchild==0) { /* left child is a leaf */    if (pr->rchild==0) p->table[0]=2; /* and so is the right child */    else { /* no, it isn't */      for (k=2;k<=pr->table[0];k++) p->table[1+k]=pr->table[k];      p->table[0]=pr->table[0]+1;    }  }@+else if (pr->rchild==0) { /* right child is a leaf */    for (k=2;k<=pl->table[0];k++) p->table[1+k]=pl->table[k];    p->table[0]=pl->table[0]+1;  }@+else { /* neither child is a leaf */    @<Set |p->table[2]|, |p->table[3]|, \dots\ to convolution of      |pl| and |pr| table entries@>;    p->table[0]=pl->table[0]+pr->table[0];  }}@ @<Set |p->table[2]|, |p->table[3]|, \dots\ to convolution...@>=p->table[2]=0;for (j=pl->table[0];j;j--) {@+register long t=pl->table[j];  for (k=pr->table[0];k;k--)    p->table[j+k]+=t*pr->table[k];}@ @<Stochastically determine the number of leaves to grow...@>={@+register long ss,rr;  j=0; /* we will set |j=1| if scaling is necessary at the root */  if (p==node_block) {    ss=0;    if (l>29 && l<67) {      j=1; /* more than $2^{31}$ possibilities exist */      for (k=(l>pr->table[0]? l-pr->table[0]: 1);k<=pl->table[0] && k<l;k++)        ss+=((pl->table[k]+0x3ff)>>10)*pr->table[l-k];              /* scale with $d_0=1024$, $d_1=1$ */    }@+else      for (k=(l>pr->table[0]? l-pr->table[0]: 1);k<=pl->table[0] && k<l;k++)        ss+=pl->table[k]*pr->table[l-k];  }@+else ss=p->table[l];  rr=gb_unif_rand(ss);  if (j)    for (ss=0,k=(l>pr->table[0]? l-pr->table[0]: 1);ss<=rr;k++)      ss+=((pl->table[k]+0x3ff)>>10)*pr->table[l-k];  else for (ss=0,k=(l>pr->table[0]? l-pr->table[0]: 1);ss<=rr;k++)      ss+=pl->table[k]*pr->table[l-k];  pl->tag=k-1;@+pr->tag=l-k+1;}@* Arcs.In the general case, we have to combine some of the basic micro-sectorsinto macro-sectors by adding together the appropriate input/outputcoefficients. This is a bottom-up pruning process.Suppose |p| is being formed as the union of |pl| and~|pr|.Then the arcs leading out of |p| are obtained by summing the numberson arcs leading out of |pl| and~|pr|; the arcs leading into |p| areobtained by summing the numbers on arcs leading into |pl| and~|pr|;the arcs from |p| to itself are obtained by summing the four numberson arcs leading from |pl| or~|pr| to |pl| or~|pr|.We maintain the |node_index| table so that its non-|NULL| entriescontain all the currently active nodes. When |pl| and~|pr| arebeing pruned in favor of~|p|, node |p|~inherits |pl|'s place in|node_index|; |pr|'s former place becomes~|NULL|.@<Put the appropriate arcs into the graph@>=@<Prune the sectors that are used in macro-sectors, and form  the lists of SIC sector codes@>;@<Make the special nodes invisible if they are omitted, visible otherwise@>;@<Compute individual thresholds for each chosen sector@>;{@+register Vertex *v=new_graph->vertices+n;  for (k=MAX_N;k;k--)    if ((p=node_index[k])!=NULL) {      vert_index[k]=--v;      v->name=gb_save_string(p->title);      v->SIC_codes=p->SIC_list;      v->sector_total=p->total;    }@+else vert_index[k]=NULL;  if (v!=new_graph->vertices)    panic(impossible); /* bug in algorithm; this can't happen */  for (j=MAX_N;j;j--)    if ((p=node_index[j])!=NULL) {@+register Vertex *u=vert_index[j];      for (k=MAX_N;k;k--)        if ((v=vert_index[k])!=NULL)          if (p->table[k]!=0 && p->table[k]>node_index[k]->thresh) {            gb_new_arc(u,v,1L);            u->arcs->flow=p->table[k];          }      }}@ @<Private v...@>=static Vertex *vert_index[MAX_N+1]; /* the vertex assigned to an SIC code */@ The theory underlying this step is the following, for integers$a,b,c,d$ with $b,d>0$:$$ {a\over b}>{c\over d} \qquad\iff\qquad  a>\biggl\lfloor{b\over d}\biggr\rfloor\,c +       \biggl\lfloor{(b\bmod d)c\over d}\biggr\rfloor\,.$$In our case, $b=\hbox{|p->total|}$ and $c=threshold\le d=65536=2^{16}$, hencethe multiplications cannot overflow. (But they can come awfully darn close.)@<Compute individual thresholds for each chosen sector@>=for (k=MAX_N;k;k--)  if ((p=node_index[k])!=NULL) {    if (threshold==0) p->thresh=-99999999;    else p->thresh=((p->total>>16)*threshold)+      (((p->total&0xffff)*threshold)>>16);  }@ @<Prune the sectors that are used in macro-sectors, and form  the lists of SIC sector codes@>=for (p=node_index[ADJ_SEC];p>=node_block;p--) { /* bottom up */  if (p->SIC) { /* original leaf */    p->SIC_list=gb_virgin_arc();    p->SIC_list->len=p->SIC;  }@+else {    pl=p+1;@+pr=p->rchild;    if (p->tag==0) p->tag=pl->tag+pr->tag;    if (p->tag<=1) @<Replace |pl| and |pr| by their union, |p|@>;  }}    @ @<Replace |pl| and |pr| by their union, |p|@>={@+register Arc *a=pl->SIC_list;  register long jj=pl->SIC, kk=pr->SIC;  p->SIC_list=a;  while (a->next) a=a->next;  a->next=pr->SIC_list;  for (k=MAX_N;k;k--)    if ((q=node_index[k])!=NULL) {      if (q!=pl && q!=pr) q->table[jj]+=q->table[kk];      p->table[k]=pl->table[k]+pr->table[k];    }  p->total=pl->total+pr->total;  p->SIC=jj;  p->table[jj]+=p->table[kk];  node_index[jj]=p;  node_index[kk]=NULL;}@ If the \.{Users} vertex is not omitted, we need to compute eachsector's total final demand, which is calculated so that the row sumsand column sums of the input/output coefficients come out equal. We'vealready computed the column sum, |p->total|; we've also computed|p->table[1]+@[@t\hbox{$\cdots$}@>@]+p->table[ADJ_SEC]|, and put it into|p->table[MAX_N]|. So now we want to replace |p->table[MAX_N]| by|p->total-p->table[MAX_N]|. As remarked earlier, this quantity mightbe negative.In the special node |p| for the \.{Users} vertex, the preliminaryprocessing has made |p->total=0|; moreover, |p->table[MAX_N]| is thesum of value added, or GNP.  We want to switch those fields.We don't have to set the |tag| fields to 1 in the special nodes, becausethe remaining parts of the arc-generation algorithm don't look at those fields.@<Make the special nodes invisible if they are omitted, visible otherwise@>=if (omit==2) node_index[ADJ_SEC]=node_index[MAX_N]=NULL;else if (omit==1) node_index[MAX_N]=NULL;else {  for (k=ADJ_SEC;k;k--)    if ((p=node_index[k])!=NULL) p->table[MAX_N]=p->total-p->table[MAX_N];  p=node_index[MAX_N]; /* the special node */  p->total=p->table[MAX_N];  p->table[MAX_N]=0;}      @* Index. As usual, we close with an index thatshows where the identifiers of \\{gb\_econ} are defined and used.

⌨️ 快捷键说明

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