189 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			189 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
								 | 
							
								/* DISTRIB.C - Procedures for handling distributions over numbers. */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* Copyright (c) 1995-2012 by Radford M. Neal and Peter Junteng Liu.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * Permission is granted for anyone to copy, use, modify, and distribute
							 | 
						||
| 
								 | 
							
								 * these programs and accompanying documents for any purpose, provided
							 | 
						||
| 
								 | 
							
								 * this copyright notice is retained and prominently displayed, and note
							 | 
						||
| 
								 | 
							
								 * is made of any changes made to these programs.  These programs and
							 | 
						||
| 
								 | 
							
								 * documents are distributed without any warranty, express or implied.
							 | 
						||
| 
								 | 
							
								 * As the programs were written for research purposes only, they have not
							 | 
						||
| 
								 | 
							
								 * been tested to the degree that would be advisable in any important
							 | 
						||
| 
								 | 
							
								 * application.  All use of these programs is entirely at the user's own
							 | 
						||
| 
								 | 
							
								 * risk.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <stdlib.h>
							 | 
						||
| 
								 | 
							
								#include <stdio.h>
							 | 
						||
| 
								 | 
							
								#include <math.h>
							 | 
						||
| 
								 | 
							
								#include <string.h>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include "alloc.h"
							 | 
						||
| 
								 | 
							
								#include "distrib.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* CREATE A DISTRIBUTION AS SPECIFIED IN A STRING.  Space for the distribution
							 | 
						||
| 
								 | 
							
								   is allocated; the string is not freed. 
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   The string must consist either of a single positive integer, representing
							 | 
						||
| 
								 | 
							
								   the distribution over just that number, or have a form such as the
							 | 
						||
| 
								 | 
							
								   following:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      5x2/3.5x1/1.5x4
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   This specifies a distribution over 3 numbers, 2, 1, and 4, specified by
							 | 
						||
| 
								 | 
							
								   the second number in each pair, with proportions of 0.5, 0.35, and 0.15, 
							 | 
						||
| 
								 | 
							
								   respectively, specified by the first number in each pair.  The actual
							 | 
						||
| 
								 | 
							
								   proportions are found by dividing the first number in each pair by the sum 
							 | 
						||
| 
								 | 
							
								   of these numbers.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   The distrib type represents the distribution list.  It stores a pointer to 
							 | 
						||
| 
								 | 
							
								   an array of distrib_entry elements along with the length of this array.
							 | 
						||
| 
								 | 
							
								   Each distrib_entry contains a (number,proportion) pair.
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								distrib *distrib_create
							 | 
						||
| 
								 | 
							
								( char *c		/* String describing distribution over numbers */
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  distrib *d;
							 | 
						||
| 
								 | 
							
								  char *str, *tstr;
							 | 
						||
| 
								 | 
							
								  int i, n, scan_num, size;
							 | 
						||
| 
								 | 
							
								  double prop, sum;
							 | 
						||
| 
								 | 
							
								  char junk;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* Check for special case of a single number. */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (sscanf(c,"%d%c",&n,&junk)==1 && n>0)
							 | 
						||
| 
								 | 
							
								  { tstr = chk_alloc ( (int)(4.1+log10(n)), sizeof(*tstr));
							 | 
						||
| 
								 | 
							
								    sprintf(tstr,"1x%d",n);
							 | 
						||
| 
								 | 
							
								    d = distrib_create(tstr);
							 | 
						||
| 
								 | 
							
								    free(tstr);
							 | 
						||
| 
								 | 
							
								    return d;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* Initial scan of string for size and proper usage. */
							 | 
						||
| 
								 | 
							
								  
							 | 
						||
| 
								 | 
							
								  str = c;
							 | 
						||
| 
								 | 
							
								  size = 0;
							 | 
						||
| 
								 | 
							
								  sum = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  d = chk_alloc(1, sizeof *d);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  for (;;)
							 | 
						||
| 
								 | 
							
								  { 
							 | 
						||
| 
								 | 
							
								    scan_num = sscanf(str, "%lgx%d%c", &prop, &n, &junk);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if ((scan_num!=2 && scan_num!=3) || prop<=0 || n<=0)
							 | 
						||
| 
								 | 
							
								    { return 0;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (scan_num==3 && junk!='/')
							 | 
						||
| 
								 | 
							
								    { return 0;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    size += 1;
							 | 
						||
| 
								 | 
							
								    sum += prop;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (scan_num==2)
							 | 
						||
| 
								 | 
							
								    { break;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    else
							 | 
						||
| 
								 | 
							
								    { str = (char*)strchr(str, '/') + 1;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  /* Allocate memory for the list and fill it in */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  d->size = size;
							 | 
						||
| 
								 | 
							
								  d->list = chk_alloc (size, sizeof(distrib_entry));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  i = 0;
							 | 
						||
| 
								 | 
							
								  str = c;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  for (;;)
							 | 
						||
| 
								 | 
							
								  { 
							 | 
						||
| 
								 | 
							
								    scan_num = sscanf(str, "%lgx%d%c", &prop, &n, &junk);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    d->list[i].prop = prop/sum;
							 | 
						||
| 
								 | 
							
								    d->list[i].num = n;
							 | 
						||
| 
								 | 
							
								    i += 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (scan_num==2)
							 | 
						||
| 
								 | 
							
								    { break;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    else if (scan_num==3)
							 | 
						||
| 
								 | 
							
								    { str = (char*)strchr(str, '/') + 1;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    else
							 | 
						||
| 
								 | 
							
								    { abort();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return d;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* FREE SPACE OCCUPIED A DISTRIBUTION LIST. */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void distrib_free
							 | 
						||
| 
								 | 
							
								( distrib *d 	/* List to free */
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								{ free(d->list);
							 | 
						||
| 
								 | 
							
								  free(d);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* RETURN THE MAXIMUM NUMBER IN A DISTRIBUTION LIST.  Returns 0 if the list 
							 | 
						||
| 
								 | 
							
								   pointer is 0. */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								int distrib_max 
							 | 
						||
| 
								 | 
							
								( distrib *d	/* List to examine */
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								{ 
							 | 
						||
| 
								 | 
							
								  int i;
							 | 
						||
| 
								 | 
							
								  int cur;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (d==0) return 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  cur = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  for (i = 1; i<d->size; i++)
							 | 
						||
| 
								 | 
							
								  { if (d->list[i].num > d->list[cur].num)
							 | 
						||
| 
								 | 
							
								    { cur = i;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return d->list[cur].num;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* TEST PROGRAM. */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifdef TEST_DISTRIB
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								main
							 | 
						||
| 
								 | 
							
								( int argc,
							 | 
						||
| 
								 | 
							
								  char **argv
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  distrib *d;
							 | 
						||
| 
								 | 
							
								  int i, j;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  for (i = 1; i<argc; i++)
							 | 
						||
| 
								 | 
							
								  { d = distrib_create(argv[i]);
							 | 
						||
| 
								 | 
							
								    if (d==0)
							 | 
						||
| 
								 | 
							
								    { printf("Error\n\n");
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    else
							 | 
						||
| 
								 | 
							
								    { for (j = 0; j<distrib_size(d); j++)
							 | 
						||
| 
								 | 
							
								      { printf("%.3f %d\n",distrib_prop(d,j),distrib_num(d,j));
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      printf("\n");
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  exit(0);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#endif
							 |