VIS
|
00001 00048 #include "puresatInt.h" 00049 00050 00051 /*---------------------------------------------------------------------------*/ 00052 /* Constant declarations */ 00053 /*---------------------------------------------------------------------------*/ 00054 00055 /*---------------------------------------------------------------------------*/ 00056 /* Structure declarations */ 00057 /*---------------------------------------------------------------------------*/ 00058 00059 /*---------------------------------------------------------------------------*/ 00060 /* Type declarations */ 00061 /*---------------------------------------------------------------------------*/ 00062 00063 /*---------------------------------------------------------------------------*/ 00064 /* Variable declarations */ 00065 /*---------------------------------------------------------------------------*/ 00066 00067 /*---------------------------------------------------------------------------*/ 00068 /* Macro declarations */ 00069 /*---------------------------------------------------------------------------*/ 00070 00073 /*---------------------------------------------------------------------------*/ 00074 /* Static function prototypes */ 00075 /*---------------------------------------------------------------------------*/ 00076 00079 /*---------------------------------------------------------------------------*/ 00080 /* Definition of exported functions */ 00081 /*---------------------------------------------------------------------------*/ 00082 00083 /*---------------------------------------------------------------------------*/ 00084 /* Definition of internal functions */ 00085 /*---------------------------------------------------------------------------*/ 00086 00087 00100 void 00101 PureSat_CheckInvariant( 00102 Ntk_Network_t *network, 00103 array_t *InvariantFormulaArray, 00104 int verbosity, 00105 int dbgLevel, 00106 FILE *dbgOut, 00107 boolean printInputs, 00108 boolean incremental, 00109 boolean sss, 00110 boolean flatIP, 00111 int speed) 00112 { 00113 int result,i; 00114 Ctlp_Formula_t *invFormula; 00115 Ctlsp_Formula_t *invFormula_sp; 00116 PureSat_Manager_t * pm = PureSatManagerAlloc(); 00117 00118 pm->incre = incremental; 00119 pm->verbosity = verbosity; 00120 pm->dbgLevel = dbgLevel; 00121 pm->sss = sss; 00122 pm->printInputs = printInputs; 00123 pm->dbgOut = dbgOut; 00124 00125 switch(speed){ 00126 case 0: 00127 break; 00128 case 1: 00129 pm->Switch = 0; 00130 break; 00131 case 2: 00132 pm->Switch = 0; 00133 pm->CoreRefMin = 0; 00134 break; 00135 case 3: 00136 pm->Switch = 0; 00137 pm->CoreRefMin = 0; 00138 pm->RefPredict = 0; 00139 break; 00140 case 4: 00141 pm->Switch = 0; 00142 pm->CoreRefMin = 0; 00143 pm->RefPredict = 0; 00144 pm->Arosat = 0; 00145 break; 00146 default: 00147 pm->Switch = 0; 00148 pm->CoreRefMin = 0; 00149 pm->RefPredict = 0; 00150 pm->Arosat = 0; 00151 break; 00152 } 00153 00154 arrayForEachItem(Ctlp_Formula_t *, InvariantFormulaArray, i, invFormula) { 00155 /* if(Ctlsp_isCtlFormula(invFormula))*/ 00156 invFormula_sp = Ctlsp_CtlFormulaToCtlsp(invFormula); 00157 if(sss) 00158 /*SSS-base Puresat algorithm*/ 00159 result = PureSatCheckInv_SSS(network,invFormula_sp,pm); 00160 else 00161 if(flatIP) 00162 /*Interpolation algorithm without abstraction refinement*/ 00163 result = PureSatCheckInv_FlatIP(network,invFormula_sp,pm); 00164 else 00165 /*Interpolation-based Puresat algorithm*/ 00166 result = PureSatCheckInv_IP(network,invFormula_sp,pm); 00167 if(result){ 00168 (void) fprintf(vis_stdout, "# INV: formula passed --- "); 00169 Ctlsp_FormulaPrint(vis_stdout, (invFormula_sp)); 00170 fprintf(vis_stdout, "\n"); 00171 } 00172 else{ 00173 if(pm->dbgLevel != 2) 00174 { 00175 (void) fprintf(vis_stdout, "# INV: formula failed --- "); 00176 Ctlsp_FormulaPrint(vis_stdout, (invFormula_sp)); 00177 fprintf(vis_stdout, "\n"); 00178 } 00179 } 00180 } 00181 PureSatManagerFree(pm); 00182 } 00183 00184 00185 00186 /*---------------------------------------------------------------------------*/ 00187 /* Definition of internal functions */ 00188 /*---------------------------------------------------------------------------*/ 00189 00203 boolean PureSatCheckInv_SSS(Ntk_Network_t * network, 00204 Ctlsp_Formula_t *ltlFormula, 00205 PureSat_Manager_t *pm) 00206 { 00207 lsGen gen; 00208 st_generator *stGen; 00209 int NumofCurrentLatch=0,Length=0,tmp=0,NumofLatch=0,i,j,k; 00210 int addtoAbs=0,latchThreshHold=10000,RingPosition=0; 00211 int oldLength=0, beginPosition=0; 00212 int NumInSecondLevel =0; 00213 array_t * visibleArray = array_alloc(char *,0); 00214 array_t * invisibleArray = array_alloc(char *,0); 00215 array_t * refinement = array_alloc(char*,0); 00216 array_t * CoiArray,* ConClsArray; 00217 array_t * arrayRC = NULL; 00218 array_t *tmpRefinement; 00219 array_t *tmpRefinement1; 00220 char * nodeName; 00221 Ntk_Node_t * node, *latch; 00222 boolean ExistSimplePath = TRUE,ExistACE = FALSE; 00223 boolean realRefine=TRUE; 00224 boolean needSorting = FALSE, firstTime = TRUE; 00225 mAig_Manager_t *maigManager; 00226 BmcOption_t * options; 00227 BmcCnfStates_t *cnfstate; 00228 bAigEdge_t property; 00229 st_table * nodeToMvfAigTable; 00230 double t1,t2, t0,t3; 00231 long *space; 00232 PureSat_IncreSATManager_t * pism1,*pism2; 00233 satArray_t *saved; 00234 00235 pm->supportTable = st_init_table(st_ptrcmp,st_ptrhash); 00236 pm->CoiTable = st_init_table(st_ptrcmp,st_ptrhash); 00237 pm->vertexTable = st_init_table(strcmp, st_strhash); 00238 pism1 = PureSatIncreSATManagerAlloc(pm); 00239 pism2 = PureSatIncreSATManagerAlloc(pm); 00240 t0 = util_cpu_ctime(); 00241 00242 options = BmcOptionAlloc(); 00243 options->satInFile = BmcCreateTmpFile(); 00244 options->satOutFile = BmcCreateTmpFile(); 00245 NumofCurrentLatch=0; 00246 t1 = util_cpu_ctime(); 00247 PureSatBmcGetCoiForLtlFormula(network, ltlFormula,pm->CoiTable); 00248 PureSatGenerateSupportTable(network,pm); 00249 t2 = util_cpu_ctime(); 00250 if(pm->verbosity>=2) 00251 fprintf(vis_stdout,"Generate DFS: %g\n",(double)((t2-t1)/1000.0)); 00252 00253 pm->vertexTable = (st_table *)PureSatCreateInitialAbstraction(network,ltlFormula,&NumofCurrentLatch,pm); 00254 00255 pm->AbsTable = st_init_table(st_ptrcmp,st_ptrhash); 00256 00257 Ntk_NetworkForEachLatch(network, gen, node){ 00258 if (st_lookup_int(pm->CoiTable, node, &tmp)){ 00259 NumofLatch++; 00260 nodeName = Ntk_NodeReadName(node); 00261 if(st_lookup(pm->vertexTable,nodeName,NIL(char *))) 00262 { 00263 array_insert_last(char *,visibleArray,nodeName); 00264 latch = Ntk_NetworkFindNodeByName(network,nodeName); 00265 PureSatComputeTableForLatch(network,pm->AbsTable,latch); 00266 } 00267 else 00268 array_insert_last(char *,invisibleArray,nodeName); 00269 } 00270 } 00271 if(pm->verbosity>=1){ 00272 fprintf(vis_stdout,"visiblearray has %d latches\n",array_n(visibleArray)); 00273 fprintf(vis_stdout,"invisibleArray has %d latches\n",array_n(invisibleArray)); 00274 } 00275 CoiArray = array_dup(visibleArray); 00276 array_append(CoiArray,invisibleArray); 00277 00278 maigManager = Ntk_NetworkReadMAigManager(network); 00279 if (maigManager == NIL(mAig_Manager_t)) { 00280 (void) fprintf(vis_stdout, "** bmc error: run build_partition_maigs command first\n"); 00281 BmcOptionFree(options); 00282 return 1; 00283 } 00284 nodeToMvfAigTable =(st_table *) Ntk_NetworkReadApplInfo(network, 00285 MVFAIG_NETWORK_APPL_KEY); 00286 00287 /*build property clauses*/ 00288 if (Ctlsp_isPropositionalFormula(ltlFormula)) 00289 property = BmcCreateMaigOfPropFormula(network, maigManager, ltlFormula); 00290 else 00291 property = BmcCreateMaigOfPropFormula(network, maigManager, ltlFormula->left); 00292 00293 if (property == mAig_NULL){ 00294 fprintf(vis_stderr,"property = NULL\n"); 00295 exit(0); 00296 } 00297 00298 property = bAig_Not(property); 00299 00300 while(NumofCurrentLatch < NumofLatch) 00301 { 00302 t3 = util_cpu_ctime(); 00303 if(pm->verbosity>=1) 00304 fprintf(vis_stdout,"Current Latches: %d, COI latches:%d,NEW Length:%d,\n", 00305 NumofCurrentLatch,NumofLatch,pm->Length); 00306 if(pm->verbosity>=2) 00307 fprintf(vis_stdout,"General time: %g\n",(double)((t3-t0)/1000.0)); 00308 //tmpRefinement1 = array_alloc(char *,0); 00309 firstTime = TRUE; 00310 pm->SufAbsTable = st_init_table(st_ptrcmp,st_ptrhash); 00311 if(realRefine){ 00312 arrayForEachItem(char *,refinement,i,nodeName) 00313 { 00314 latch = Ntk_NetworkFindNodeByName(network,nodeName); 00315 PureSatComputeTableForLatch(network,pm->AbsTable,latch); 00316 } 00317 array_append(visibleArray,refinement); 00318 latchThreshHold=(int)((double)(array_n(CoiArray)-array_n(visibleArray))/(double)4)+1; 00319 00320 addtoAbs =(int)((double)(array_n(CoiArray)-array_n(visibleArray))/(double)5)+1; 00321 addtoAbs = addtoAbs >50 ? 50: addtoAbs; 00322 00323 array_free(invisibleArray); 00324 invisibleArray = array_alloc(char *,0); 00325 st_foreach_item_int(pm->CoiTable,stGen,&latch,&i) 00326 { 00327 nodeName = Ntk_NodeReadName(latch); 00328 if(!st_lookup(pm->vertexTable,nodeName,0)) 00329 array_insert_last(char *,invisibleArray,nodeName); 00330 } 00331 t1 = util_cpu_ctime(); 00332 PureSatGetCoiForVisibleArray_Ring(network, visibleArray,RingPosition, pm->CoiTable); 00333 RingPosition = array_n(visibleArray); 00334 arrayRC = PureSatGenerateRingFromAbs(network,pm,invisibleArray,&NumInSecondLevel); 00335 if(pm->verbosity>=2){ 00336 fprintf(vis_stdout,"NumInSecondLevel is %d ",NumInSecondLevel); 00337 fprintf(vis_stdout,"latchThreshHold is %d\n",latchThreshHold); 00338 } 00339 latchThreshHold = (latchThreshHold <= NumInSecondLevel) ? latchThreshHold:NumInSecondLevel; 00340 if(pm->verbosity>=2){ 00341 fprintf(vis_stdout,"New latchThreshHold is %d\n",latchThreshHold); 00342 } 00343 t2 = util_cpu_ctime(); 00344 if(pm->verbosity>=2){ 00345 fprintf(vis_stdout,"Generate Ring: %g\n",(double)((t2-t1)/1000.0)); 00346 } 00347 array_free(refinement); 00348 }/* if(realRefine)*/ 00349 00350 realRefine =FALSE; /* means no ref, just Length++.*/ 00351 t1 = util_cpu_ctime(); 00352 if((ExistSimplePath = 00353 PureSatExistASimplePath(network,pism1,visibleArray,property,pm))) 00354 { 00355 t2 = util_cpu_ctime(); 00356 if(pm->verbosity>=2) 00357 fprintf(vis_stdout,"Solve on Simple Path: %g\n",(double)((t2-t1)/1000.0)); 00358 pism1->oldLength = pm->Length; 00359 pism1->Length = pm->Length; 00360 pism1->beginPosition = array_n(visibleArray); 00361 if(pm->verbosity>=1) 00362 fprintf(vis_stdout, "Simple Path Exists, length = %d\n",pm->Length); 00363 00364 /*check Abs Model*/ 00365 t1 = util_cpu_ctime(); 00366 ExistACE = PureSatIncreExistCE(network,pism2,visibleArray,property,pm); 00367 if(pm->verbosity>=2) 00368 fprintf(vis_stdout,"beginPosition2: %d, oldLength2 %d\n",pism2->beginPosition, pism2->oldLength); 00369 t2 = util_cpu_ctime(); 00370 if(pm->verbosity>=2) 00371 fprintf(vis_stdout,"Solve on Abs model: %g\n",(double)((t2-t1)/1000.0)); 00372 pism2->oldLength = pm->Length; 00373 pism2->Length = pm->Length; 00374 pism2->beginPosition = array_n(visibleArray); 00375 needSorting = FALSE; 00376 00377 /*keep a record of previous position for refine's use*/ 00378 oldLength = pism2->oldLength; 00379 beginPosition = pism2->beginPosition; 00380 00381 /* while(ExistACE) 00382 loop until find sufficient set*/ 00383 if(ExistACE) 00384 { 00385 if(pm->verbosity>=1) 00386 fprintf(vis_stdout,"found Abstract Counterexample at length %d\n", pm->Length); 00387 cnfstate = BmcCnfClausesFreeze(pism2->cnfClauses); 00388 pism2->propertyPos = cnfstate->nextIndex; 00389 00390 /*store the conflict clauses*/ 00391 ConClsArray = array_alloc(int,0); 00392 00393 /*if incremental */ 00394 if(pm->incre){ 00395 if(pism2->cm->savedConflictClauses){ 00396 saved = pism2->cm->savedConflictClauses; 00397 for(i=0, space=saved->space; i<saved->num; i++, space++){ 00398 array_insert_last(int,ConClsArray,*space); 00399 } 00400 } 00401 } 00402 realRefine = TRUE; 00403 00404 /*incrementally check Concrete Model*/ 00405 tmpRefinement = array_alloc(char *,0); 00406 if(pm->verbosity>=2) 00407 fprintf(vis_stdout,"Begin building a new abstract model\n"); 00408 for(i=0;i<array_n(arrayRC);i=i+latchThreshHold) 00409 { 00410 if(i>0) 00411 latchThreshHold = array_n(arrayRC)-latchThreshHold; 00412 for(j=0;j<latchThreshHold;j++) 00413 { 00414 if((i+j)<array_n(arrayRC)) 00415 { 00416 nodeName = array_fetch(char *,arrayRC,i+j); 00417 array_insert_last(char *,tmpRefinement,nodeName); 00418 if(pm->verbosity>=2) 00419 fprintf(vis_stdout, "picking %s\n",nodeName); 00420 } 00421 else 00422 break; 00423 }/* for(j=0;*/ 00424 tmpRefinement1=array_dup(visibleArray); 00425 array_append(tmpRefinement1,tmpRefinement); 00426 00427 t1 = util_cpu_ctime(); 00428 pism2->cm->option->incAll = 1; 00429 pism2->cm->option->incTraceObjective = 0; 00430 pism2->cm->option->incPreserveNonobjective = 0; 00431 if(PureSatIncreExistCEForRefineOnAbs(network,pism2,tmpRefinement1,property,firstTime,pm)) { 00432 t2 = util_cpu_ctime(); 00433 if(pm->verbosity>=2) 00434 fprintf(vis_stdout,"time for finding a sufficient set on model: %g\n",(double)((t2-t1)/1000.0)); 00435 if((i+j)>=array_n(arrayRC)){ 00436 if(pm->verbosity>=1) 00437 fprintf(vis_stdout,"found real counterexamples\n"); 00438 if(pm->dbgLevel>=1){ 00439 options->printInputs = TRUE; 00440 BmcPrintCounterExample(network, nodeToMvfAigTable, pism2->cnfClauses, 00441 pm->result, pm->Length, pm->CoiTable, options, 00442 NIL(array_t)); 00443 array_free(pm->result); 00444 pm->result = NIL(array_t); 00445 } 00446 array_free(tmpRefinement1); 00447 array_free(tmpRefinement); 00448 BmcOptionFree(options); 00449 PureSatIncreSATManagerFree(pm,pism1); 00450 PureSatIncreSATManagerFree(pm,pism2); 00451 /*PureSatManagerFree(pm);*/ 00452 array_free(CoiArray); 00453 array_free(visibleArray); 00454 return FALSE; 00455 } 00456 else{ 00457 if(pm->result!=NIL(array_t)){ 00458 array_free(pm->result); 00459 pm->result = NIL(array_t); 00460 } 00461 } 00462 } 00463 else{ 00464 t2 = util_cpu_ctime(); 00465 if(pm->verbosity>=1) 00466 fprintf(vis_stdout,"found a sufficient model\n"); 00467 if(pm->verbosity>=2) 00468 fprintf(vis_stdout,"time for finding a sufficient set on model: %g\n",(double)((t2-t1)/1000.0)); 00469 firstTime = FALSE; 00470 arrayForEachItem(char *,tmpRefinement1,k,nodeName){ 00471 node = Ntk_NetworkFindNodeByName(network, nodeName); 00472 if(!st_lookup(pm->SufAbsTable,node,NIL(char *))) 00473 st_insert(pm->SufAbsTable,node, (char *)0); 00474 else{ 00475 fprintf(vis_stderr,"wrong in sufabstable \n"); 00476 exit(0); 00477 } 00478 } 00479 pism2->beginPosition = array_n(tmpRefinement1); 00480 pism2->oldLength = Length; 00481 array_free(tmpRefinement1); 00482 break; 00483 } 00484 pism2->beginPosition = array_n(tmpRefinement1); 00485 array_free(tmpRefinement1); 00486 pism2->oldLength = Length; 00487 } /*for(i=0;i<array_n(arrayRC)*/ 00488 00489 /*recover the conflict clauses and incremental SAT option*/ 00490 pism2->cm->option->incAll = 0; 00491 pism2->cm->option->incTraceObjective = 1; 00492 pism2->cm->option->incPreserveNonobjective = 1; 00493 00494 /*if incremental*/ 00495 if(pm->incre){ 00496 if(pism2->cm->savedConflictClauses) 00497 sat_ArrayFree(pism2->cm->savedConflictClauses); 00498 pism2->cm->savedConflictClauses = sat_ArrayAlloc(16); 00499 arrayForEachItem(int, ConClsArray,i,tmp) 00500 sat_ArrayInsert(pism2->cm->savedConflictClauses,tmp); 00501 } 00502 array_free(tmpRefinement); 00503 t1 = util_cpu_ctime(); 00504 refinement = PureSatRefineOnAbs(network,pm,property,addtoAbs); 00505 t2 = util_cpu_ctime(); 00506 if(pm->verbosity>=2) 00507 fprintf(vis_stdout,"time for RefOnAbs: %g\n",(double)((t2-t1)/1000.0)); 00508 st_free_table(pm->SufAbsTable); 00509 pm->SufAbsTable = NIL(st_table); 00510 00511 /*adjust parameters*/ 00512 NumofCurrentLatch+=array_n(refinement); 00513 pm->Length++; 00514 pism1->Length++; 00515 pism2->Length++; 00516 BmcCnfClausesRestore(pism2->cnfClauses, cnfstate); 00517 pism2->beginPosition = beginPosition; 00518 pism2->oldLength = oldLength; 00519 FREE(cnfstate); 00520 }/* if(pism2->cm->status == SAT_SAT)*/ 00521 else /*if(pism2->cm->status != SAT_SAT)*/ 00522 { 00523 if(pm->verbosity>=1) 00524 fprintf(vis_stdout,"no Abstract Counterexample at length %d \n",pm->Length); 00525 pm->Length++; 00526 pism1->Length++; 00527 pism2->Length++; 00528 st_free_table(pm->SufAbsTable); 00529 pm->SufAbsTable = NIL(st_table); 00530 } 00531 } /*if(ExistSimplePath)*/ 00532 else /* if no simple path*/ 00533 { 00534 t2 = util_cpu_ctime(); 00535 if(pm->verbosity>=2) 00536 fprintf(vis_stdout,"Solve on Simple Path: %g\n",(double)((t2-t1)/1000.0)); 00537 if(pm->verbosity>=1) 00538 fprintf(vis_stdout,"simple Path doesn't exist, exit\n"); 00539 BmcOptionFree(options); 00540 PureSatIncreSATManagerFree(pm,pism1); 00541 PureSatIncreSATManagerFree(pm,pism2); 00542 PureSatManagerFree(pm); 00543 array_free(CoiArray); 00544 array_free(visibleArray); 00545 return TRUE; 00546 } 00547 }/* while(NumofCurrentLatch < NumofLatch)*/ 00548 /*st_free_table(AbsTable);*/ 00549 00550 /*Now go to the concrete model*/ 00551 if(pm->verbosity>=1) 00552 fprintf(vis_stdout,"reach concrete model\n"); 00553 array_append(visibleArray,refinement); 00554 array_free(refinement); 00555 while(PureSatExistASimplePath(network,pism1,visibleArray,property,pm)) 00556 { 00557 pism1->oldLength = pism1->Length; 00558 pism1->beginPosition = array_n(visibleArray); 00559 if(PureSatExistCE(network,pism2,options,visibleArray,property,pm,1)) { 00560 if(pm->verbosity>=1) 00561 fprintf(vis_stdout,"found real counterexample of length:%d\n",pm->Length); 00562 if(pm->dbgLevel>=1){ 00563 options->printInputs = TRUE; 00564 BmcPrintCounterExample(network, nodeToMvfAigTable, pism2->cnfClauses, 00565 pm->result, pm->Length, pm->CoiTable, options, 00566 NIL(array_t)); 00567 } 00568 BmcOptionFree(options); 00569 PureSatIncreSATManagerFree(pm,pism1); 00570 PureSatIncreSATManagerFree(pm,pism2); 00571 /*PureSatManagerFree(pm);*/ 00572 array_free(CoiArray); 00573 array_free(visibleArray); 00574 return FALSE; 00575 } 00576 else 00577 { 00578 pism2->oldLength = Length; 00579 pm->Length++; 00580 pism1->Length++; 00581 pism2->Length++; 00582 pism2->beginPosition = array_n(visibleArray); 00583 } 00584 } 00585 00586 BmcOptionFree(options); 00587 PureSatIncreSATManagerFree(pm,pism1); 00588 PureSatIncreSATManagerFree(pm,pism2); 00589 /*PureSatManagerFree(pm);*/ 00590 array_free(CoiArray); 00591 array_free(visibleArray); 00592 return TRUE; 00593 } 00594 00609 void PureSatCmdParse(int argc, 00610 char **argv, 00611 PureSat_Manager_t *pm) 00612 00613 { 00614 int c, incre; 00615 00616 util_getopt_reset(); 00617 while ((c = util_getopt(argc, argv, "t:i:h:v:I:")) != EOF) { 00618 switch(c) { 00619 case 'i': 00620 strcpy(pm->ltlFileName,util_strsav(util_optarg)); 00621 break; 00622 case 't' : 00623 pm->timeOutPeriod = atoi(util_optarg); 00624 break; 00625 case 'v': 00626 pm->verbosity = atoi(util_optarg); 00627 break; 00628 case 'I': 00629 incre = atoi(util_optarg); 00630 pm->incre = (incre==0)? FALSE:TRUE; 00631 break; 00632 case 'h': 00633 goto usage; 00634 default: 00635 goto usage; 00636 } 00637 } 00638 return; 00639 usage: 00640 (void) fprintf(vis_stderr, "usage: abrf [-h][-i ltlfile][-t timeout]\n"); 00641 (void) fprintf(vis_stderr, " -i \tName of LTL file.\n"); 00642 (void) fprintf(vis_stderr, " -t \ttimeout.\n"); 00643 (void) fprintf(vis_stderr, " -v \tverbosity for more information. \n"); 00644 (void) fprintf(vis_stderr, " -I \tincremental SAT switch. \n"); 00645 (void) fprintf(vis_stderr, "\t\t0 for non-incremental, other values for incremental\n"); 00646 (void) fprintf(vis_stderr, " -h \tprint the command usage\n"); 00647 00648 } 00649 00650 /*---------------------------------------------------------------------------*/ 00651 /* Definition of static functions */ 00652 /*---------------------------------------------------------------------------*/