1 /*
2  *   Copyright (C) 1988-1990 Yale University
3  *
4  *   This work is distributed in the hope that it will be useful; you can
5  *   redistribute it and/or modify it under the terms of the
6  *   GNU General Public License as published by the Free Software Foundation;
7  *   either version 2 of the License,
8  *   or any later version, on the following conditions:
9  *
10  *   (a) YALE MAKES NO, AND EXPRESSLY DISCLAIMS
11  *   ALL, REPRESENTATIONS OR WARRANTIES THAT THE MANUFACTURE, USE, PRACTICE,
12  *   SALE OR
13  *   OTHER DISPOSAL OF THE SOFTWARE DOES NOT OR WILL NOT INFRINGE UPON ANY
14  *   PATENT OR
15  *   OTHER RIGHTS NOT VESTED IN YALE.
16  *
17  *   (b) YALE MAKES NO, AND EXPRESSLY DISCLAIMS ALL, REPRESENTATIONS AND
18  *   WARRANTIES
19  *   WHATSOEVER WITH RESPECT TO THE SOFTWARE, EITHER EXPRESS OR IMPLIED,
20  *   INCLUDING,
21  *   BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A
22  *   PARTICULAR
23  *   PURPOSE.
24  *
25  *   (c) LICENSEE SHALL MAKE NO STATEMENTS, REPRESENTATION OR WARRANTIES
26  *   WHATSOEVER TO
27  *   ANY THIRD PARTIES THAT ARE INCONSISTENT WITH THE DISCLAIMERS BY YALE IN
28  *   ARTICLE
29  *   (a) AND (b) above.
30  *
31  *   (d) IN NO EVENT SHALL YALE, OR ITS TRUSTEES, DIRECTORS, OFFICERS,
32  *   EMPLOYEES AND
33  *   AFFILIATES BE LIABLE FOR DAMAGES OF ANY KIND, INCLUDING ECONOMIC DAMAGE OR
34  *   INJURY TO PROPERTY AND LOST PROFITS, REGARDLESS OF WHETHER YALE SHALL BE
35  *   ADVISED, SHALL HAVE OTHER REASON TO KNOW, OR IN FACT SHALL KNOW OF THE
36  *   POSSIBILITY OF THE FOREGOING.
37  *
38  */
39 
40 /* -----------------------------------------------------------------
41 FILE:	    window.c
42 DESCRIPTION:new window limiter routines due to Jimmy Lamm
43 CONTENTS:   DOUBLE eval_ratio(percentWindow)
44 		DOUBLE *percentWindow ;
45 	    init_control()
46 	    pick_position(INT *, INT *, int, int)
47 	    update_control(a)
48 	    fix_window()
49 	    update_window_size( iteration )
50 		DOUBLE iteration ;
51 DATE:	    Feb 29, 1988
52 REVISIONS:  Apr 23, 1988 - added fix_window for low temp anneal
53 	    Oct 21, 1988 - changed steps per cell and add graph func.
54 	    Oct 26, 1988 - add pick_neighborhood and fixed bug in
55 		pick_position.
56 	    Nov 20, 1988 - fixed chip aspect ratio.
57 	    Jan 15, 1989 - added update_window_size, and new eval ratio
58 		for curve-fit controller.
59 	    Jan 29, 1989 - changed to YmsgG.
60 	    Mar 02, 1989 - move temp defintions to temp.h
61 	    Apr 09, 1989 - fixed bug in pick_position and
62 		pick_neighborhood so that cells can't jump outside region.
63 ----------------------------------------------------------------- */
64 
65 #include <custom.h>
66 #include <temp.h>
67 #include <yalecad/debug.h>
68 
69 #define AC0 0.90		/*** 0.75 ***/
70 #define AC1 0.44		/*** 0.44 ***/
71 #define AC2 0.06		/*** 0.08 ***/
72 
73 #define PT1 0.15		/*** 0.15 ***/
74 #define PT2 0.52		/*** 0.52 ***/
75 #define PT3 1.00		/*** 1.00 ***/
76 
77 #define LAC1 (log(AC1))
78 #define LAC2 (log(AC2))
79 
80 #define STEPSPERCEL 0.01           /* was 0.01 */
81 
82 #define TABLIMIT 4096		/*** simple table lookup for log. ***/
83 #define TABSHIFT 19
84 #define TABMASK 0xfff
85 #define TABOFFSET 0x40000
86 #define RANDFACT (1.0 / INT_MAX)
87 #define PICK_INT(l,u) (((l)<(u)) ? ((RAND % ((u)-(l)+1))+(l)) : (l))
88 
89 static DOUBLE xadjustmentS,xalS,min_xalphaS,max_xalphaS;/** x control **/
90 static DOUBLE yadjustmentS,yalS,min_yalphaS,max_yalphaS;/** y control **/
91 static DOUBLE total_stepS;
92 static DOUBLE log_tabS[TABLIMIT];
93 static DOUBLE tauXS, tauYS ; /* exp. decay time constants for window */
94 
eval_ratio(iteration)95 DOUBLE eval_ratio( iteration )
96 INT iteration ;
97 {
98     if( iteration >= TURNOFFT ){
99 	return( (DOUBLE) 1.0 ) ;
100     } else if( iteration < 0 ){
101 	return( (DOUBLE) 0.0 ) ;
102     } else {
103 	return( (DOUBLE) iteration / TURNOFFT ) ;
104     }
105 }
106 
107 /* *****************************************************************
108    init_control - initialize range limiter.
109 */
init_control(first)110 void init_control(first)
111 BOOL first ;
112 {
113     INT i;
114     DOUBLE area ;
115 
116 #define FRACTION  0.10
117 
118     /*** initialize move generation parameters ***/
119     /* minxspan = mean_width + 3 sigma variation  */
120     area = mean_cellAreaG + 3 * dev_cellAreaG ;
121 
122     /*** average min. window size ***/
123     min_xalphaS = 0.5 * sqrt( area / chipaspectG ) ;
124     min_yalphaS = 0.5 * sqrt( chipaspectG * area ) ;
125 
126     min_xalphaS = MIN( min_xalphaS, FRACTION * (DOUBLE) bdxlengthG ) ;
127     min_yalphaS = MIN( min_yalphaS, FRACTION * (DOUBLE) bdylengthG ) ;
128     OUT2( "min_xalpha:%4.2lf\n", min_xalphaS ) ;
129     OUT2( "min_yalpha:%4.2lf\n", min_yalphaS ) ;
130 
131     if (init_accG >= 0.44) {
132 	max_xalphaS = bdxlengthG;	/*** average max. window size ***/
133 	max_yalphaS = bdylengthG;	/*** average max. window size ***/
134     } else {
135 	max_xalphaS = min_xalphaS;	/*** no adjustments ***/
136 	max_yalphaS = min_yalphaS;
137     }
138 
139     total_stepS = STEPSPERCEL * numcellsG;
140     xadjustmentS = (max_xalphaS - min_xalphaS) / total_stepS;
141     yadjustmentS = (max_yalphaS - min_yalphaS) / total_stepS;
142 
143     xalS = max_xalphaS;
144     yalS = max_yalphaS;
145 
146     if (first) {
147 	xalS = max_xalphaS;
148 	yalS = max_yalphaS;
149 	/* determine tauXS */
150 	tauXS = - log( (min_xalphaS/max_xalphaS)) / (MEDTEMP - HIGHTEMP) ;
151 	tauYS = - log( (min_yalphaS/max_yalphaS)) / (MEDTEMP - HIGHTEMP) ;
152     }
153 
154     /*** prepare lookup table ***/
155     for (i=0; i<TABLIMIT; i++)
156 	log_tabS[i] = log(((i << TABSHIFT) + TABOFFSET) * RANDFACT);
157 }
158 
159 /* *****************************************************************
160    pick_positon - pick place to move within range limiter.
161 */
pick_position(x,y,ox,oy)162 void pick_position(x,y,ox,oy)
163 INT *x,*y,ox,oy;
164 {
165     register INT i,m,n;
166 
167     /* get exponentially distributed random number around old x */
168     for (i=0; i<2; i++) {
169 	m = RAND;
170 	n = -xalS * log_tabS[(m >> TABSHIFT) & TABMASK];
171 	if (m & 0x10000){
172 	    n = -n;
173 	}
174 	n += ox;
175 	/* check for inside core */
176 	if (n >= blocklG && n <= blockrG){
177 	    /* hate to use a goto here but it saves another test */
178 	    goto DONEX ;
179 	}
180     }
181     /* by default -we have failed. Use boundary */
182     if (n < blocklG) {
183 	if (ox > blockrG){
184 	    ox = blockrG;
185 	} else if (ox < blocklG){
186 	    ox = blocklG;
187 	}
188 	n = PICK_INT(blocklG,ox);
189     } else if (n > blockrG) {
190 	if (ox < blocklG){
191 	    ox = blocklG;
192 	} else if (ox > blockrG){
193 	    ox = blockrG;
194 	}
195 	n = PICK_INT(ox,blockrG);
196     }
197 DONEX:  *x = n;
198 
199     /* get exponentially distributed random number around old y */
200     for (i=0; i<2; i++) {
201 	m = RAND;
202 	n = -yalS * log_tabS[(m >> TABSHIFT) & TABMASK];
203 	if (m & 0x10000){
204 	    n = -n;
205 	}
206 	n += oy;
207 	/* check for inside core */
208 	if (n >= blockbG && n <= blocktG){
209 	    *y = n;
210 	    return;
211 	}
212     }
213     /* if fail use boundary */
214     if (n < blockbG) {
215 	if (oy > blocktG){
216 	    oy = blocktG;
217 	} else if (oy < blockbG){
218 	    oy = blockbG;
219 	}
220 	n = PICK_INT(blockbG,oy);
221     } else if (n > blocktG) {
222 	if (oy < blockbG){
223 	    oy = blockbG;
224 	} else if (oy > blocktG){
225 	    oy = blocktG;
226 	}
227 	n = PICK_INT(oy,blocktG);
228     }
229     *y = n;
230 }
231 
232 /* *****************************************************************
233    pick_neighborhood - pick place to move within neighborhood while
234    still using range limiter.
235 */
pick_neighborhood(x,y,ox,oy,fixptr)236 void pick_neighborhood(x,y,ox,oy,fixptr)
237 INT *x,*y,ox,oy;
238 FIXEDBOXPTR fixptr ;
239 {
240     register INT i,m,n;
241     INT xjump, yjump ;
242 
243 #define DIV_2   >> 1
244 
245     /* check if x range limiter is smaller than neighborhood */
246     if( xalS > fixptr->xspan ){
247 	ox = fixptr->xcenter ;  /* jump from center of neighborhood */
248 	xjump = fixptr->xspan DIV_2 ; /* average jump half the xspan */
249     } else {
250 	/* we must use range limiter and jump from old coordinates */
251 	xjump = xalS ;
252     }
253 
254     /* get exponentially distributed random number around old x */
255     for (i=0; i<2; i++) {
256 	m = RAND;
257 	n = -xjump * log_tabS[(m >> TABSHIFT) & TABMASK];
258 	if (m & 0x10000){
259 	    n = -n;
260 	}
261 	n += ox;
262 	/* check for inside neighborhood */
263 	if (n >= fixptr->x1 && n <= fixptr->x2 ){
264 	    /* hate to use a goto here but it saves another test */
265 	    goto DONEX ;
266 	}
267     }
268     /* by default - we have failed. Use neighborhood boundary */
269     if (n < fixptr->x1 ) {
270 	if (ox > fixptr->x2 ){
271 	    ox = fixptr->x2 ;
272 	} else if (ox < fixptr->x1 ){
273 	    ox = fixptr->x1 ;
274 	}
275 	n = PICK_INT(fixptr->x1 ,ox);
276     } else if (n > fixptr->x2 ) {
277 	if (ox < fixptr->x1 ){
278 	    ox = fixptr->x1 ;
279 	} else if (ox > fixptr->x2 ){
280 	    ox = fixptr->x2 ;
281 	}
282 	n = PICK_INT(ox,fixptr->x2 );
283     }
284     DONEX:  *x = n;
285 
286     /* check if y range limiter is smaller than neighborhood */
287     if( yalS > fixptr->yspan ){
288 	oy = fixptr->ycenter ;  /* jump from center of neighborhood */
289 	yjump = fixptr->yspan DIV_2 ; /* average jump half the yspan */
290     } else {
291 	/* we must use range limiter and jump from old coordinates */
292 	yjump = yalS ;
293     }
294     /* get exponentially distributed random number around old y */
295     for (i=0; i<2; i++) {
296 	m = RAND;
297 	n = -yjump * log_tabS[(m >> TABSHIFT) & TABMASK];
298 	if (m & 0x10000){
299 	    n = -n;
300 	}
301 	n += oy;
302 	/* check for inside core */
303 	if (n >= fixptr->y1 && n <= fixptr->y2){
304 	    *y = n;
305 	    return;
306 	}
307     }
308     /* if fail use neighborhood boundary */
309     if (n < fixptr->y1) {
310 	if (oy > fixptr->y2){
311 	    oy = fixptr->y2;
312 	} else if (oy < fixptr->y1){
313 	    oy = fixptr->y1;
314 	}
315 	n = PICK_INT(fixptr->y1,oy);
316     } else if (n > fixptr->y2) {
317 	if (oy < fixptr->y1){
318 	    oy = fixptr->y1;
319 	} else if (oy > fixptr->y2){
320 	    oy = fixptr->y2;
321 	}
322 	n = PICK_INT(oy,fixptr->y2);
323     }
324     *y = n;
325 } /* end pick_neighborhood */
326 
update_window_size(iteration)327 void update_window_size( iteration )
328 DOUBLE iteration ;
329 {
330     if( iteration <= HIGHTEMP ){
331 	xalS = max_xalphaS ;
332 	yalS = max_yalphaS ;
333     } else if( iteration <= MEDTEMP ){
334 	/* exponential decay xal and yal */
335 	/* --------------------------------------------------------
336 	    xal = max_xalpha * exp( - tauXS * ( iteration - HIGHTEMP ))
337 	    yal = max_yalpha * exp( - tauYS * ( iteration - HIGHTEMP ))
338 	   -------------------------------------------------------- */
339 	xalS = yalS = iteration - HIGHTEMP ;
340 	xalS *= - tauXS ;
341 	xalS = max_xalphaS * exp( xalS ) ;
342 
343 	yalS *= - tauYS ;
344 	yalS = max_yalphaS * exp( yalS ) ;
345 
346     } else {  /* low temp */
347 	xalS = min_xalphaS ;
348 	yalS = min_yalphaS ;
349     }
350    /*
351 	OUT5(" xal = %4.2le  yal = %4.2le stepsG = %4.2le T=%4.2le\n",
352 	   xalS, yalS, stepsG, TG );
353     */
354 
355 }
356 
fix_window()357 void fix_window()
358 {
359     /*** set window to minimum for low temp anneal ***/
360     xalS = min_xalphaS;
361     yalS = min_yalphaS;
362 }
363 
364 /* *****************************************************************
365    save_window - save window parameters for restart
366 */
367 /* static declaration for restoring state for low temp anneal */
368 static DOUBLE ws_xalS;
369 static DOUBLE ws_yalS;
370 static DOUBLE ws_ratioS ;
371 
save_window(fp)372 void save_window( fp )
373 FILE *fp ;
374 {
375     if( fp ){  /* if a file pointer is given write to file */
376 	fprintf(fp,"# window parameters:\n") ;
377 	fprintf(fp,"%f %f %f\n",xalS,yalS,ratioG );
378     } else { /* otherwise save in memory */
379 	ws_xalS = xalS ;
380 	ws_yalS = yalS ;
381 	ws_ratioS = ratioG ;
382     }
383 }
384 
385 /* *****************************************************************
386    read_window - read window parameters for restart
387 */
read_window(fp)388 INT read_window( fp )
389 FILE *fp ;
390 {
391     INT errors = 0 ;
392     if( fp ){  /* if file pointer given restore from file */
393 	fscanf(fp,"%[ #:a-zA-Z]\n",YmsgG ); /* throw away comment */
394 	fscanf(fp,"%lf %lf %lf\n",&xalS,&yalS,&ratioG);
395 	/* try to detect errors */
396 	if( xalS < 0.0 ){
397 	    M(ERRMSG,"read_window","Restart file: xal negative\n") ;
398 	    errors++ ;
399 	}
400 	if( yalS < 0.0 ){
401 	    M(ERRMSG,"read_window","Restart file: yal negative\n") ;
402 	    errors++ ;
403 	}
404 	if( ratioG < 0.0 ){
405 	    M(ERRMSG,"read_window","Restart file: ratio negative\n") ;
406 	    errors++ ;
407 	}
408 	if( ratioG > 1.0 ){
409 	    M(ERRMSG,"read_window","Restart file: ratio > 1\n") ;
410 	    errors++ ;
411 	}
412     } else {  /* restore from memory */
413 	xalS = ws_xalS ;
414 	yalS = ws_yalS ;
415 	ratioG = ws_ratioS ;
416     }
417     return(errors) ;
418 } /* end read_window */
419