1 /*
2  * Copyright (C) 2007 Bill Cox
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
17  */
18 
19 /*--------------------------------------------------------------------------------------------------
20   This module routes the schema.  There is a grid consisting of "Bundles", or bunds representing
21   locations in the grid.  There are horizontal and vertical tracks of bunds that overlap.  In
22   horizontal tracks, adjacencies are build horizontally, but not vertically.  When horizontal
23   tracks cross vertical tracks, there are adjacencies between the overlapping horizontal and
24   vertical bundles.
25 --------------------------------------------------------------------------------------------------*/
26 #include "dw.h"
27 
28 static uint32 dwOverconstraints;
29 static uint32 dwRows, dwCols;
30 static uint32 dwOverconstraintPenalty;
31 static uint32 dwMaxBucket;
32 static dvClass dwSourceClass, dwTargetClass;
33 static dwBundArray dwRandBunds;
34 static dwRelationshipArray dwRandRelationships;
35 
36 #define dwIndexHBund(x, y) dwIndex2Bund(dwCols*(y) + (x))
37 #define dwIndexVBund(x, y) dwIndex2Bund(dwRows*dwCols + dwRows*(x) + (y))
38 
39 /* Bund adj iterator */
40 #define dwFindAdjOtherBund(adj, bund) (dwAdjGetFromBund(adj) == (bund) ? \
41     dwAdjGetToBund(adj) : dwAdjGetFromBund(adj))
42 #define dwBundGetFirstAdj(bund) (dwBundGetFirstInAdj(bund) != dwAdjNull? \
43     dwBundGetFirstInAdj(bund) : dwBundGetFirstOutAdj(bund))
44 #define dwBundGetNextBundAdj(bund, adj) (dwAdjGetToBund(adj) == (bund)? \
45     (dwAdjGetNextBundInAdj(adj) != dwAdjNull? \
46     dwAdjGetNextBundInAdj(adj) : dwBundGetFirstOutAdj(bund)) : \
47     dwAdjGetNextBundOutAdj(adj))
48 #define dwForeachBundAdj(bund, adj) \
49     for(adj = dwBundGetFirstAdj(bund); (adj != dwAdjNull); \
50     adj = dwBundGetNextBundAdj(bund, adj))
51 #define dwEndBundAdj
52 
53 /*--------------------------------------------------------------------------------------------------
54   Create a new bundle.
55 --------------------------------------------------------------------------------------------------*/
dwBundCreate(uint32 x,uint32 y)56 static dwBund dwBundCreate(
57     uint32 x,
58     uint32 y)
59 {
60     dwBund bund = dwBundAlloc();
61 
62     dwBundSetX(bund, x);
63     dwBundSetY(bund, y);
64     return bund;
65 }
66 
67 /*--------------------------------------------------------------------------------------------------
68   Create a new adj.
69 --------------------------------------------------------------------------------------------------*/
dwAdjCreate(dwBund bund1,dwBund bund2)70 static dwAdj dwAdjCreate(
71     dwBund bund1,
72     dwBund bund2)
73 {
74     dwAdj adj = dwAdjAlloc();
75 
76     dwBundInsertOutAdj(bund1, adj);
77     dwBundInsertInAdj(bund2, adj);
78     return adj;
79 }
80 
81 /*--------------------------------------------------------------------------------------------------
82   Build the routing graph of horizontal and vertical tracks of bundles.  We create first horizontal
83   bundles from lower left to the top, then vertical tracks from lower left to the right.
84 
85     gridsPerCol = dwSchemaGetColWidth(schema)
86     gridsPerRow = dwSchemaGetRowHeight(schema)
87     cols = (dwSchemaGetCols(schema) + 1)*dwGridsPerCol
88     rows = (dwSchemaGetRows(schema) + 1)*dwGridsPerRow
89     hBundIndex = bundY*cols + bundX
90     vBundIndex = rows*cols + bundX*rows + bundY
91 --------------------------------------------------------------------------------------------------*/
buildRoutingGraph(dvSchema schema)92 static void buildRoutingGraph(
93     dvSchema schema)
94 {
95     dwBund bund, prevBund, hBund;
96     uint32 gridsPerCol = dwSchemaGetColWidth(schema);
97     uint32 gridsPerRow = dwSchemaGetRowHeight(schema);
98     uint32 x, y;
99 
100     dwCols = (dwSchemaGetCols(schema) + 1)*gridsPerCol;
101     dwRows = (dwSchemaGetRows(schema) + 1)*gridsPerRow;
102     /* Build horizontal tracks */
103     for(y = 0; y < dwRows; y++) {
104         prevBund = dwBundNull;
105         for(x = 0; x < dwCols; x++) {
106             bund = dwBundCreate(x, y);
107             if(prevBund != dwBundNull) {
108                 dwAdjCreate(prevBund, bund);
109             }
110             prevBund = bund;
111         }
112     }
113     /* Build vertical tracks */
114     for(x = 0; x < dwCols; x++) {
115         prevBund = dwBundNull;
116         for(y = 0; y < dwRows; y++) {
117             bund = dwBundCreate(x, y);
118             if(prevBund != dwBundNull) {
119                 dwAdjCreate(prevBund, bund);
120             }
121             /* Connect this vertical bund to it's overlapping horizontal bund */
122             hBund = dwIndexHBund(x, y);
123             dwAdjCreate(bund, hBund);
124             dwBundSetOverlappingBund(bund, hBund);
125             dwBundSetOverlappingBund(hBund, bund);
126             prevBund = bund;
127         }
128     }
129 }
130 
131 /*--------------------------------------------------------------------------------------------------
132   Add the bundle to the class, and then block all adjacencies to the bundle, exept in the direction
133   specified.
134 --------------------------------------------------------------------------------------------------*/
addClassBund(dvClass theClass,dwBund bund,uint32 x,uint32 y)135 static void addClassBund(
136     dvClass theClass,
137     dwBund bund,
138     uint32 x,
139     uint32 y)
140 {
141     dwBund otherBund;
142     dwAdj adj;
143 
144     dwClassInsertBund(theClass, bund);
145     dwForeachBundAdj(bund, adj) {
146         otherBund = dwFindAdjOtherBund(adj, bund);
147         if(dwBundGetX(otherBund) != x || dwBundGetY(otherBund) != y) {
148             dwAdjSetBlocked(adj, true);
149         }
150     } dwEndBundAdj;
151 }
152 
153 /*--------------------------------------------------------------------------------------------------
154   Add the Class --> Bund relationship for this class.  Also set the class's bounding box in grid
155   units.
156 --------------------------------------------------------------------------------------------------*/
addClassToGraph(dvSchema schema,dvClass theClass)157 static void addClassToGraph(
158     dvSchema schema,
159     dvClass theClass)
160 {
161     dwBund bund;
162     uint32 width = dwClassGetWidth(theClass);
163     uint32 height = dwClassGetHeight(theClass);
164     uint32 gridsPerCol = dwSchemaGetColWidth(schema);
165     uint32 gridsPerRow = dwSchemaGetRowHeight(schema);
166     uint32 x = (dwClassGetX(theClass) + 1)*gridsPerCol - (width >> 1);
167     uint32 y = (dwClassGetY(theClass) + 1)*gridsPerRow - (height >> 1);
168     uint32 dX, dY;
169 
170     /* In case we had a previous run, the class could be pointing to a deleted bundle */
171     dwClassSetFirstBund(theClass, dwBundNull);
172     dwClassSetLeft(theClass, x);
173     dwClassSetBottom(theClass, y);
174     dwClassSetRight(theClass, x + width);
175     dwClassSetTop(theClass, y + height);
176     /* Add the top and bottom to the vertical grid. */
177     for(dX = 0; dX <= width; dX++) {
178         bund = dwIndexVBund(x + dX, y);
179         addClassBund(theClass, bund, x + dX, y - 1);
180         bund = dwIndexVBund(x + dX, y + height);
181         addClassBund(theClass, bund, x + dX, y + height + 1);
182     }
183     /* Add the left and right to the horizontal grid. */
184     for(dY = 0; dY <= height; dY++) {
185         bund = dwIndexHBund(x, y + dY);
186         addClassBund(theClass, bund, x - 1, y + dY);
187         bund = dwIndexHBund(x + width, y + dY);
188         addClassBund(theClass, bund, x + width + 1, y + dY);
189     }
190 }
191 
192 /*--------------------------------------------------------------------------------------------------
193   Mark bundles within 2 adjs of a class as nearby.  This effects the cost for routing.
194 --------------------------------------------------------------------------------------------------*/
markBundsNearClass(dvClass theClass)195 static void markBundsNearClass(
196     dvClass theClass)
197 {
198     dwBund bund1, bund2;
199     dwAdj adj1;
200 
201     dwForeachClassBund(theClass, bund1) {
202         dwForeachBundAdj(bund1, adj1) {
203             bund2 = dwFindAdjOtherBund(adj1, bund1);
204             dwBundSetNearClass(bund2, true);
205         } dwEndBundAdj;
206     } dwEndClassBund;
207 }
208 
209 /*--------------------------------------------------------------------------------------------------
210   Build the Class --> Bund relationship for all classes in the schema.
211 --------------------------------------------------------------------------------------------------*/
addClassesToGraph(dvSchema schema)212 static void addClassesToGraph(
213     dvSchema schema)
214 {
215     dvClass theClass;
216 
217     dwForeachClassArrayClass(dwClasses, theClass) {
218         addClassToGraph(schema, theClass);
219         markBundsNearClass(theClass);
220     } dwEndClassArrayClass;
221 }
222 
223 /*--------------------------------------------------------------------------------------------------
224   Add the bundle to the bunket with the given cost.
225 --------------------------------------------------------------------------------------------------*/
addBucketBund(uint32 cost,dwBund bund)226 static void addBucketBund(
227     uint32 cost,
228     dwBund bund)
229 {
230     dwBucket bucket;
231 
232     utAssert(dwBundGetClass(bund) == dwSourceClass || dwBundGetPrevBund(bund) != dwBundNull);
233     while(cost >= dwUsedBucket()) {
234         (void)dwBucketAlloc();
235     }
236     bucket = dwIndex2Bucket(cost);
237     dwBucketInsertBund(bucket, bund);
238     dwMaxBucket = utMax(cost, dwMaxBucket);
239 }
240 
241 /*--------------------------------------------------------------------------------------------------
242   Find a bundle cost.  It's more expensive to be overconstrained, or close to a class or another
243   relationship.
244 --------------------------------------------------------------------------------------------------*/
findBundCost(dwBund bund)245 static uint32 findBundCost(
246     dwBund bund)
247 {
248     dwBund overlappingBund = dwBundGetOverlappingBund(bund);
249     uint32 cost = 0;
250 
251     if(dwBundGetFirstRoute(bund) != dwRouteNull) {
252         cost = dwOverconstraintPenalty;
253     }
254     if(dwBundGetFirstRoute(overlappingBund) != dwRouteNull) {
255         cost++;
256     }
257     if(dwBundNearClass(bund) || dwBundNearClass(overlappingBund)) {
258         cost += 4;
259     }
260     return cost;
261 }
262 
263 /*--------------------------------------------------------------------------------------------------
264   Initialize the wave on the source class.
265 --------------------------------------------------------------------------------------------------*/
initWave(void)266 static void initWave(void)
267 {
268     dwBund bund;
269     uint32 cost;
270 
271     dwForeachClassBund(dwSourceClass, bund) {
272         cost = findBundCost(bund);
273         dwBundSetPrevBund(bund, dwBundNull);
274         addBucketBund(cost, bund);
275     } dwEndClassBund;
276 }
277 
278 /*--------------------------------------------------------------------------------------------------
279   Initialize the wave on the source class for a self-relationship.  Just find a random starting
280   point.
281 --------------------------------------------------------------------------------------------------*/
initSelfWave(void)282 static void initSelfWave(void)
283 {
284     dwBund bund, randSourceBund;
285     uint32 xRandBund;
286 
287     dwBundArraySetUsedBund(dwRandBunds, 0);
288     dwForeachClassBund(dwSourceClass, bund) {
289         dwBundSetPrevBund(bund, dwBundNull);
290         if(dwBundGetFirstRoute(bund) == dwRouteNull) {
291             dwBundArrayAppendBund(dwRandBunds, bund);
292         }
293     } dwEndClassBund;
294     xRandBund = utRandN(dwBundArrayGetUsedBund(dwRandBunds));
295     randSourceBund = dwBundArrayGetiBund(dwRandBunds, xRandBund);
296     addBucketBund(0, randSourceBund);
297 }
298 
299 /*--------------------------------------------------------------------------------------------------
300   Randomize bundles in the bucket, and add them to the dwRandBunds array.
301 --------------------------------------------------------------------------------------------------*/
randomizeBundArray(dwBundArray bunds)302 static void randomizeBundArray(
303     dwBundArray bunds)
304 {
305     dwBund bund, otherBund;
306     uint32 xBund, xOtherBund;
307     uint32 numBunds = dwBundArrayGetUsedBund(bunds);
308 
309     for(xBund = 0; xBund < numBunds; xBund++) {
310         xOtherBund = xBund + utRandN(numBunds - xBund);
311         bund = dwBundArrayGetiBund(bunds, xBund);
312         otherBund = dwBundArrayGetiBund(bunds, xOtherBund);
313         dwBundArraySetiBund(bunds, xBund, otherBund);
314         dwBundArraySetiBund(bunds, xOtherBund, bund);
315     }
316 }
317 
318 /*--------------------------------------------------------------------------------------------------
319   Randomize bundles in the bucket, and add them to the dwRandBunds array.
320 --------------------------------------------------------------------------------------------------*/
randomizeBunds(dwBucket bucket)321 static void randomizeBunds(
322     dwBucket bucket)
323 {
324     dwBund bund;
325 
326     dwBundArraySetUsedBund(dwRandBunds, 0);
327     dwForeachBucketBund(bucket, bund) {
328         dwBundArrayAppendBund(dwRandBunds, bund);
329     } dwEndBucketBund;
330     randomizeBundArray(dwRandBunds);
331 }
332 
333 /*--------------------------------------------------------------------------------------------------
334   Expand the bundle into nearest neighbors randomly.  If we find a target bund, return it.
335 --------------------------------------------------------------------------------------------------*/
expandBund(dwBund bund)336 static dwBund expandBund(
337     dwBund bund)
338 {
339     dvClass theClass;
340     dwBund otherBund;
341     dwAdj adj;
342     uint32 cost = dwBucket2Index(dwBundGetBucket(bund)) + 1;
343     uint32 bundCost;
344 
345     dwForeachBundAdj(bund, adj) {
346         otherBund = dwFindAdjOtherBund(adj, bund);
347         if(dwBundGetBucket(otherBund) == dwBucketNull && !dwAdjBlocked(adj)) {
348             theClass = dwBundGetClass(otherBund);
349             if(theClass == dwTargetClass) {
350                 dwBundSetPrevBund(otherBund, bund);
351                 return otherBund;
352             }
353             if(theClass == dvClassNull) {
354                 bundCost = cost + findBundCost(otherBund);
355                 dwBundSetPrevBund(otherBund, bund);
356                 addBucketBund(bundCost, otherBund);
357             }
358         }
359     } dwEndBundAdj;
360     return dwBundNull;
361 }
362 
363 /*--------------------------------------------------------------------------------------------------
364   Expand the bucket of bundles into nearest neighbors randomly.  Return any target we find.
365 --------------------------------------------------------------------------------------------------*/
expandBucket(dwBucket bucket)366 static dwBund expandBucket(
367     dwBucket bucket)
368 {
369     dwBund bund, targetBund;
370 
371     randomizeBunds(bucket);
372     dwForeachBundArrayBund(dwRandBunds, bund) {
373         targetBund = expandBund(bund);
374         if(targetBund != dwBundNull) {
375             return targetBund;
376         }
377     } dwEndBundArrayBund;
378     return dwBundNull;
379 }
380 
381 /*--------------------------------------------------------------------------------------------------
382   Expand the wave to the target.  Return the target we hit.
383 --------------------------------------------------------------------------------------------------*/
expandToTarget(void)384 static dwBund expandToTarget(void)
385 {
386     dwBucket bucket;
387     dwBund target;
388 
389     uint32 xBucket = 0;
390 
391     while(true) {
392         bucket = dwIndex2Bucket(xBucket);
393         target = expandBucket(bucket);
394         if(target != dwBundNull) {
395             return target;
396         }
397         xBucket++;
398     }
399     return dwBundNull; /* Dummy return */
400 }
401 
402 /*--------------------------------------------------------------------------------------------------
403   Follow the back pointers from the target to source, building routes.
404 --------------------------------------------------------------------------------------------------*/
dwBuildRoute(dvRelationship relationship,dwBund bund)405 static dwRoute dwBuildRoute(
406     dvRelationship relationship,
407     dwBund bund)
408 {
409     dwRoute route = dwRouteAlloc();
410 
411     if(dwBundGetFirstRoute(bund) != dwRouteNull) {
412         dwOverconstraints++;
413     }
414     dwRelationshipInsertRoute(relationship, route);
415     dwBundInsertRoute(bund, route);
416     return route;
417 }
418 
419 /*--------------------------------------------------------------------------------------------------
420   Follow the back pointers from the target to source, building routes.
421 --------------------------------------------------------------------------------------------------*/
backtrace(dvRelationship relationship,dwBund bund)422 static void backtrace(
423     dvRelationship relationship,
424     dwBund bund)
425 {
426     dwRoute route;
427 
428     do {
429         route = dwBuildRoute(relationship, bund);
430         bund = dwBundGetPrevBund(bund);
431     } while(bund != dwBundNull);
432 }
433 
434 /*--------------------------------------------------------------------------------------------------
435   Empty buckets so we can do another expansion.
436 --------------------------------------------------------------------------------------------------*/
emptyBuckets(void)437 static void emptyBuckets(void)
438 {
439     dwBucket bucket;
440     dwBund bund;
441     uint32 xBucket;
442 
443     for(xBucket = 0; xBucket <= dwMaxBucket; xBucket++) {
444         bucket = dwIndex2Bucket(xBucket);
445         utDo {
446             bund = dwBucketGetFirstBund(bucket);
447         } utWhile(bund != dwBundNull) {
448             dwBucketRemoveBund(bucket, bund);
449         } utRepeat;
450     }
451 }
452 
453 /*--------------------------------------------------------------------------------------------------
454   Route a relationship.
455 --------------------------------------------------------------------------------------------------*/
routeRelationship(dvRelationship relationship)456 static void routeRelationship(
457     dvRelationship relationship)
458 {
459     dwBund target;
460 
461     dwSourceClass = dvRelationshipGetParentClass(relationship);
462     dwTargetClass = dvRelationshipGetChildClass(relationship);
463     dwMaxBucket = 0;
464     if(dwSourceClass != dwTargetClass) {
465         initWave();
466     } else {
467         initSelfWave();
468     }
469     target = expandToTarget();
470     backtrace(relationship, target);
471     emptyBuckets();
472 }
473 
474 /*--------------------------------------------------------------------------------------------------
475   Create an initial solution, where routes just overlap without penalty.
476 --------------------------------------------------------------------------------------------------*/
initialSolution(dvSchema schema)477 static void initialSolution(
478     dvSchema schema)
479 {
480     dvRelationship relationship;
481 
482 
483     dvForeachSchemaRelationship(schema, relationship) {
484         routeRelationship(relationship);
485     } dvEndSchemaRelationship;
486 }
487 
488 /*--------------------------------------------------------------------------------------------------
489   Rip a route
490 --------------------------------------------------------------------------------------------------*/
dwRipRoute(dwRoute route)491 static void dwRipRoute(
492     dwRoute route)
493 {
494     dwBund bund = dwRouteGetBund(route);
495     dwRoute firstRoute;
496 
497     dwRouteDestroy(route);
498     firstRoute = dwBundGetFirstRoute(bund);
499     if(firstRoute != dwRouteNull) {
500         dwOverconstraints--;
501     }
502 }
503 
504 /*--------------------------------------------------------------------------------------------------
505   Randomize the relationships order
506 --------------------------------------------------------------------------------------------------*/
randomizeRelationships()507 static void randomizeRelationships()
508 {
509     dvRelationship relationship1, relationship2;
510     uint32 temp1, temp2;
511     uint32 numRelationships = dwRelationshipArrayGetUsedRelationship(dwRandRelationships);
512 
513     for(temp1 = 0; temp1 < numRelationships; temp1++) {
514         temp2 = temp1 + utRandN(numRelationships - temp1);
515         relationship1 = dwRelationshipArrayGetiRelationship(dwRandRelationships, temp1);
516         relationship2 = dwRelationshipArrayGetiRelationship(dwRandRelationships, temp2);
517         dwRelationshipArraySetiRelationship(dwRandRelationships, temp1, relationship2);
518         dwRelationshipArraySetiRelationship(dwRandRelationships, temp2, relationship1);
519     }
520 }
521 
522 /*--------------------------------------------------------------------------------------------------
523   Rip all routes of a bundle
524 --------------------------------------------------------------------------------------------------*/
dwRipRelationshipRoutes(dvRelationship relationship)525 static void dwRipRelationshipRoutes(
526     dvRelationship relationship)
527 {
528     dwRoute route;
529 
530     dwSafeForeachRelationshipRoute(relationship, route) {
531         dwRipRoute(route);
532     } dwEndSafeRelationshipRoute;
533 }
534 
535 /*--------------------------------------------------------------------------------------------------
536   Rip-up and reroute at least a few times to improve readability, or continue until DRCs are gone
537   or we give up.
538 --------------------------------------------------------------------------------------------------*/
fillRelationshipArray(dvSchema schema)539 static void fillRelationshipArray(
540     dvSchema schema)
541 {
542     dvRelationship relationship;
543 
544     dvForeachSchemaRelationship(schema, relationship) {
545         dwRelationshipArrayAppendRelationship(dwRandRelationships, relationship);
546     } dvEndSchemaRelationship;
547 
548 }
549 
550 /*--------------------------------------------------------------------------------------------------
551   Rip-up and reroute at least a few times to improve readability, or continue until DRCs are gone
552   or we give up.
553 --------------------------------------------------------------------------------------------------*/
ripUpandReroute(dvSchema schema)554 static void ripUpandReroute(
555     dvSchema schema)
556 {
557     dvRelationship relationship;
558 
559     randomizeRelationships(); /*zxcbreak*/
560     dwForeachRelationshipArrayRelationship(dwRandRelationships, relationship) { /*zxcbreak*/
561         dwRipRelationshipRoutes(relationship); /*zxcbreak*/
562         routeRelationship(relationship); /*zxcbreak*/
563     } dwEndRelationshipArrayRelationship;
564 }
565 
566 /*--------------------------------------------------------------------------------------------------
567   Route Until Completion
568 --------------------------------------------------------------------------------------------------*/
routeUntilComplete(dvSchema schema)569 static void routeUntilComplete(
570     dvSchema schema)
571 {
572     uint32 dwCycle = 0;
573 
574     fillRelationshipArray(schema); /*zxcbreak*/
575     do{
576         utIfDebug(1) {
577             utLogDebug("cycles = %d overconstraints = %d", dwCycle, dwOverconstraints);
578         }
579         dwOverconstraintPenalty++;
580         ripUpandReroute(schema);
581         dwCycle++;
582     } while((dwCycle < 10 || dwOverconstraints != 0) && dwCycle < 100);
583 }
584 
585 /*--------------------------------------------------------------------------------------------------
586   Route relationships on the schema.  Return the number of DRCs.
587 --------------------------------------------------------------------------------------------------*/
dwRouteSchema(dvSchema schema)588 uint32 dwRouteSchema(
589     dvSchema schema)
590 {
591     dwRandRelationships = dwRelationshipArrayAlloc();
592     dwBucketFreeAll();
593     dwBundFreeAll();
594     dwAdjFreeAll(); /*zxcbreak*/
595     dwRandBunds = dwBundArrayAlloc();
596     buildRoutingGraph(schema);
597     addClassesToGraph(schema);
598     dwOverconstraints = 0;
599     dwOverconstraintPenalty = 0;
600     initialSolution(schema);
601     routeUntilComplete(schema);
602     dwBundArrayFree(dwRandBunds);
603     dwRelationshipArrayFree(dwRandRelationships);
604     return dwOverconstraints;
605 }
606