/[ascend]/trunk/ascend/compiler/logrel_util.c
ViewVC logotype

Contents of /trunk/ascend/compiler/logrel_util.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2323 - (show annotations) (download) (as text)
Wed Dec 15 06:35:43 2010 UTC (14 years, 11 months ago) by jpye
File MIME type: text/x-csrc
File size: 37158 byte(s)
Refactor some more stuff from 'utilities' into 'general' with goal that 'general' never refers to 'utilities'.
1 /*
2 * Logical Relation utility functions for Ascend
3 * by Vicente Rico-Ramirez
4 * Version: $Revision: 1.16 $
5 * Version control file: $RCSfile: logrel_util.c,v $
6 * Date last modified: $Date: 1998/04/10 23:28:35 $
7 * Last modified by: $Author: ballan $
8 *
9 * This file is part of the Ascend Interpreter.
10 *
11 * The Ascend Interpreter is free software; you can redistribute
12 * it and/or modify it under the terms of the GNU General Public License as
13 * published by the Free Software Foundation; either version 2 of the
14 * License, or (at your option) any later version.
15 *
16 * ASCEND is distributed in hope that it will be
17 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with the program; if not, write to the Free Software Foundation,
23 * Inc., 675 Mass Ave, Cambridge, MA 02139 USA. Check the file named
24 * COPYING.
25 *
26 */
27 #include <math.h>
28 #include <stdarg.h>
29 #include <ascend/general/platform.h>
30 #include <ascend/general/panic.h>
31 #include <ascend/general/ascMalloc.h>
32 #include <ascend/general/list.h>
33 #include <ascend/general/dstring.h>
34
35 #include "symtab.h"
36 #include "instance_enum.h"
37 #include "functype.h"
38 #include "expr_types.h"
39 #include "instance_name.h"
40 #include "find.h"
41 #include "atomvalue.h"
42 #include "instance_io.h"
43 #include "logical_relation.h"
44 #include "logrelation.h"
45 #include "logrel_util.h"
46 #include "rel_blackbox.h"
47 #include "vlist.h"
48 #include "relation.h"
49 #include "relation_util.h"
50 #include "instance_io.h"
51 #include "instquery.h"
52 #include "visitinst.h"
53 #include "mathinst.h"
54 #include <ascend/general/mathmacros.h>
55
56 #define DEFTOLERANCE 1e-08
57
58 /*********************************************************************\
59 logical relation term queries section.
60 \*********************************************************************/
61
62 enum Expr_enum LogRelRelop(CONST struct logrelation *lrel)
63 {
64 AssertAllocatedMemory(lrel,sizeof(struct logrelation));
65 return lrel->relop;
66 }
67
68
69 unsigned long LogRelLength(CONST struct logrelation *lrel, int lhs)
70 {
71 assert(lrel!=NULL);
72 AssertAllocatedMemory(lrel,sizeof(struct logrelation));
73 if (lhs){
74 if (lrel->token.lhs) return (lrel->token.lhs_len);
75 else return 0;
76 }
77 if (lrel->token.rhs) return (lrel->token.rhs_len);
78 else return 0;
79 }
80
81 /*
82 * This query assumes the
83 * user still thinks tokens number from [1..len].
84 */
85 CONST struct logrel_term *LogRelTerm(CONST struct logrelation *lrel,
86 unsigned long int pos, int lhs)
87 {
88 assert(lrel!=NULL);
89 AssertAllocatedMemory(lrel,sizeof(struct logrelation));
90 if (lhs){
91 if (lrel->token.lhs)
92 return LOGA_TERM(&(lrel->token.lhs[pos-1]));
93 else return NULL;
94 }
95 else{
96 if (lrel->token.rhs)
97 return LOGA_TERM(&(lrel->token.rhs[pos-1]));
98 else return NULL;
99 }
100 }
101
102
103 CONST struct logrel_term
104 *NewLogRelTermF(CONST struct logrelation *lrel, unsigned long pos, int lhs)
105 {
106 assert(lrel!=NULL);
107 AssertAllocatedMemory(lrel,sizeof(struct logrelation));
108 if (lhs){
109 if (lrel->token.lhs != NULL)
110 return LOGA_TERM(&(lrel->token.lhs[pos]));
111 else return NULL;
112 } else {
113 if (lrel->token.rhs != NULL)
114 return LOGA_TERM(&(lrel->token.rhs[pos]));
115 else return NULL;
116 }
117 }
118
119
120 CONST struct logrel_term
121 *LogRelSideTermF(CONST union LogRelTermUnion *side, unsigned long pos)
122 {
123 assert(side!=NULL);
124 return LOGA_TERM(&(side[pos]));
125 }
126
127
128 enum Expr_enum LogRelTermTypeF(CONST struct logrel_term *term)
129 {
130 AssertMemory(term);
131 return term->t;
132 }
133
134 unsigned long LogTermBoolVarNumber(CONST struct logrel_term *term)
135 {
136 assert(term&&term->t == e_var);
137 AssertMemory(term);
138 return LOGBV_TERM(term)->varnum;
139 }
140
141 int LogTermBoolean(CONST struct logrel_term *term)
142 {
143 assert(term&&(term->t==e_boolean));
144 AssertMemory(term);
145 return LOGBC_TERM(term)->bvalue;
146 }
147
148 int LogTermInteger(CONST struct logrel_term *term)
149 {
150 assert(term&&(term->t==e_int));
151 AssertMemory(term);
152 return (LOGI_TERM(term)->ivalue);
153 }
154
155 int LogTermIntegerBoolValue(CONST struct logrel_term *term)
156 {
157 assert(term&&(term->t==e_int));
158 AssertMemory(term);
159 if (LOGI_TERM(term)->ivalue){
160 return 1;
161 }
162 else {
163 return 0;
164 }
165 }
166
167 int
168 LogTermBoolVar(CONST struct logrelation *lrel, CONST struct logrel_term *term)
169 {
170 return
171 GetBooleanAtomValue((struct Instance *)
172 LogRelBoolVar(lrel,LogTermBoolVarNumber(term)));
173 }
174
175 int
176 LogTermSatisfied(CONST struct logrelation *lrel,
177 CONST struct logrel_term *term,
178 int perturb,
179 struct gl_list_t *instances)
180 {
181 struct Instance *inst;
182 struct Instance *relname;
183 CONST struct relation *rel;
184 enum Expr_enum relop;
185 enum safe_err status = safe_ok;
186 double res;
187 double tol;
188 unsigned long len,n;
189 int satisfied,not_satisfied;
190 int logres;
191
192 inst = LogRelRelation(lrel,LogTermSatRelNumber(term));
193 tol = LogTermSatTolerance(term);
194
195 satisfied = 1;
196 not_satisfied = 0;
197
198 if (perturb && (instances!=NULL)) {
199 len = gl_length(instances);
200 for (n=1;n<=len;n++) {
201 relname = (struct Instance *)(gl_fetch(instances,n));
202 if (inst == relname) {
203 satisfied = 0;
204 not_satisfied = 1;
205 break;
206 }
207 }
208 }
209 switch (InstanceKind(inst)) {
210 case REL_INST:
211 status = RelationCalcResidualPostfixSafe(inst,&res);
212 if (status != safe_ok) {
213 FPRINTF(ASCERR,
214 "Something wrong while calculating a residual in Sat Expr\n");
215 return 0;
216 }
217 rel = GetInstanceRelationOnly(inst);
218 relop = RelationRelop(rel);
219 switch(relop) {
220 case e_equal:
221 if (tol != DBL_MAX) {
222 if(fabs(tol)>fabs(res)) {
223 return satisfied;
224 }
225 else {
226 return not_satisfied;
227 }
228 }
229 else {
230 if((DEFTOLERANCE)>fabs(res)) {
231 return satisfied;
232 }
233 else {
234 return not_satisfied;
235 }
236 }
237 case e_notequal:
238 if (tol != DBL_MAX) {
239 if(fabs(tol)>fabs(res)) {
240 return not_satisfied;
241 }
242 else {
243 return satisfied;
244 }
245 }
246 else {
247 if((DEFTOLERANCE)>fabs(res)) {
248 return not_satisfied;
249 }
250 else {
251 return satisfied;
252 }
253 }
254 case e_greater:
255 if (tol != DBL_MAX) {
256 if(fabs(tol)<res) {
257 return satisfied;
258 }
259 else {
260 return not_satisfied;
261 }
262 }
263 else {
264 if((DEFTOLERANCE)<res) {
265 return satisfied;
266 }
267 else {
268 return not_satisfied;
269 }
270 }
271 case e_greatereq:
272 if (tol != DBL_MAX) {
273 if(-fabs(tol)<res) {
274 return satisfied;
275 }
276 else {
277 return not_satisfied;
278 }
279 }
280 else {
281 if(-(DEFTOLERANCE)<res) {
282 return satisfied;
283 }
284 else {
285 return not_satisfied;
286 }
287 }
288 case e_less:
289 if (tol != DBL_MAX) {
290 if(-fabs(tol)>res) {
291 return satisfied;
292 }
293 else {
294 return not_satisfied;
295 }
296 }
297 else {
298 if(-(DEFTOLERANCE)>res) {
299 return satisfied;
300 }
301 else {
302 return not_satisfied;
303 }
304 }
305 case e_lesseq:
306 if (tol != DBL_MAX) {
307 if(fabs(tol)>res) {
308 return satisfied;
309 }
310 else {
311 return not_satisfied;
312 }
313 }
314 else {
315 if((DEFTOLERANCE)>res) {
316 return satisfied;
317 }
318 else {
319 return not_satisfied;
320 }
321 }
322 default:
323 FPRINTF(ASCERR,
324 "Something wrong while calculating a residual in Sat Expr\n");
325 return 0;
326 }
327 case LREL_INST:
328 if (LogRelCalcResidualPostfix(inst,&logres,perturb,instances)) {
329 FPRINTF(ASCERR,
330 "Something wrong while calculating a logical residual in Sat Expr\n");
331 return 0;
332 }
333 if(satisfied) {
334 return logres;
335 } else {
336 return (!logres);
337 }
338 default:
339 FPRINTF(ASCERR,
340 "Incorrect instance name (No Log/Relation) in Satisfied Expr\n");
341 return 0;
342 }
343 }
344
345
346 CONST struct Name *LogTermSatName(CONST struct logrel_term *term)
347 {
348 assert( term && (term->t==e_satisfied) );
349 AssertMemory(term);
350 return LOGS_TERM(term)->ncond;
351 }
352
353
354 unsigned long LogTermSatRelNumber(CONST struct logrel_term *term)
355 {
356 assert(term&&term->t == e_satisfied);
357 AssertMemory(term);
358 return LOGS_TERM(term)->relnum;
359 }
360
361
362 double LogTermSatTolerance(CONST struct logrel_term *term)
363 {
364 assert( term && (term->t==e_satisfied) );
365 AssertMemory(term);
366 return LOGS_TERM(term)->rtol;
367 }
368
369 CONST dim_type *LogTermSatDimensions(CONST struct logrel_term *term)
370 {
371 assert( term && (term->t==e_satisfied) );
372 AssertMemory(term);
373 return LOGS_TERM(term)->dim;
374 }
375
376
377 struct logrel_term *LogRelINF_Lhs(CONST struct logrelation *lrel)
378 {
379 return lrel->token.lhs_term;
380 }
381
382 struct logrel_term *LogRelINF_Rhs(CONST struct logrelation *lrel)
383 {
384 return lrel->token.rhs_term;
385 }
386
387
388
389 CONST struct gl_list_t *LogRelBoolVarList(CONST struct logrelation *lrel)
390 {
391 return (CONST struct gl_list_t *)lrel->bvars;
392 }
393
394
395 CONST struct gl_list_t *LogRelSatRelList(CONST struct logrelation *lrel)
396 {
397 return (CONST struct gl_list_t *)lrel->satrels;
398 }
399
400
401 int LogRelResidual(CONST struct logrelation *lrel)
402 {
403 assert(lrel!=NULL);
404 return lrel->logresidual;
405 }
406
407 void SetLogRelResidual(struct logrelation *lrel, int value)
408 {
409 assert(lrel!=NULL);
410 lrel->logresidual = value;
411 }
412
413 int LogRelNominal(CONST struct logrelation *lrel)
414 {
415 assert(lrel!=NULL);
416 return lrel->lognominal;
417 }
418
419 void SetLogRelNominal(struct logrelation *lrel, int value)
420 {
421 assert(lrel!=NULL);
422 lrel->lognominal = value;
423 }
424
425
426 int LogRelIsCond(CONST struct logrelation *lrel)
427 {
428 assert(lrel!=NULL);
429 return lrel->logiscond;
430 }
431
432 void SetLogRelIsCond(struct logrelation *lrel)
433 {
434 assert(lrel!=NULL);
435 lrel->logiscond = 1;
436 }
437
438
439 unsigned long NumberBoolVars(CONST struct logrelation *lrel)
440 {
441 unsigned long n;
442 assert(lrel!=NULL);
443 n = (lrel->bvars!=NULL) ? gl_length(lrel->bvars) : 0;
444 return n;
445 }
446
447 struct Instance *LogRelBoolVar(CONST struct logrelation *lrel,
448 unsigned long int varnum)
449 {
450 assert(lrel!=NULL);
451 return (struct Instance *)gl_fetch(lrel->bvars,varnum);
452 }
453
454 unsigned long NumberRelations(CONST struct logrelation *lrel)
455 {
456 unsigned long n;
457 assert(lrel!=NULL);
458 n = (lrel->satrels!=NULL) ? gl_length(lrel->satrels) : 0;
459 return n;
460 }
461
462 struct Instance *LogRelRelation(CONST struct logrelation *lrel,
463 unsigned long int relnum)
464 {
465 assert(lrel!=NULL);
466 return (struct Instance *)gl_fetch(lrel->satrels,relnum);
467 }
468
469
470 static void LogCalcDepth(CONST struct logrelation *lrel,
471 int lhs,
472 unsigned long int *depth,
473 unsigned long int *maxdepth)
474 {
475 unsigned long c,length;
476 CONST struct logrel_term *term;
477 length = LogRelLength(lrel,lhs);
478 for(c=0;c<length;c++){
479 term = NewLogRelTerm(lrel,c,lhs);
480 switch(LogRelTermType(term)){
481 case e_boolean:
482 case e_var:
483 if (++(*depth) > *maxdepth) *maxdepth = *depth;
484 break;
485 case e_satisfied:
486 case e_not:
487 break;
488 case e_and:
489 case e_or:
490 (*depth)--;
491 break;
492 default:
493 Asc_Panic(2, NULL,
494 "Don't know this type of logical relation type.\n"
495 "in function LogCalcDepth\n");
496 break;
497 }
498 }
499 }
500
501 unsigned long LogRelDepth(CONST struct logrelation *lrel)
502 {
503 unsigned long depth=0,maxdepth=0;
504 switch(LogRelRelop(lrel)){
505 case e_boolean_eq:
506 case e_boolean_neq:
507 LogCalcDepth(lrel,1,&depth,&maxdepth);
508 LogCalcDepth(lrel,0,&depth,&maxdepth);
509 assert(depth == 2);
510 break;
511 default:
512 ASC_PANIC("Unknown logical relation type.\n");
513 break;
514 }
515 return maxdepth;
516 }
517
518
519 /*********************************************************************\
520 calculation functions
521 \*********************************************************************/
522
523 /* global logical relation pointer to avoid passing a logical relation
524 * recursively
525 */
526 static struct logrelation *glob_lrel;
527
528 /* The next three functions are used for finding the value defined for
529 the tolerance in a SATISFIED term. The relation instance in the
530 satisfied term must be that given by the argument condinst provided
531 by the caller */
532
533 static int FindTolInSatisfiedTerm(struct logrelation *lrel,
534 struct logrel_term *term,
535 struct Instance *condinst,
536 double *tolerance)
537 {
538 struct Instance *inst;
539 double tol;
540
541 inst = LogRelRelation(lrel,LogTermSatRelNumber(term));
542 tol = LogTermSatTolerance(term);
543
544 if (inst == condinst) {
545 *tolerance = tol;
546 return 1;
547 } else {
548 return 0;
549 }
550 }
551
552
553 /* Note that ANY function calling FinTolInLogRelBranch should set
554 * glob_lrel to point at the logical relation being evaluated.
555 * The calling function should also set glob_lrel = NULL when it
556 * is done.
557 */
558
559 static int FindTolInLogRelBranch(struct logrel_term *term,
560 struct Instance *condinst,
561 double *tolerance)
562 {
563 assert(term != NULL);
564 switch(LogRelTermType(term)) {
565 case e_var:
566 case e_int:
567 case e_boolean:
568 return 0;
569 case e_satisfied:
570 if (FindTolInSatisfiedTerm(glob_lrel,term,condinst,tolerance)){
571 return 1;
572 } else {
573 return 0;
574 }
575 case e_and:
576 case e_or:
577 if (FindTolInLogRelBranch(LogTermBinLeft(term),condinst,tolerance)){
578 return 1;
579 } else {
580 if (FindTolInLogRelBranch(LogTermBinRight(term),condinst,tolerance)) {
581 return 1;
582 } else {
583 return 0;
584 }
585 }
586 case e_not:
587 if (FindTolInLogRelBranch(LogTermBinLeft(term),condinst,tolerance)){
588 return 1;
589 } else {
590 return 0;
591 }
592 default:
593 FPRINTF(ASCERR, "error in FindTolInLogRelBranch routine\n");
594 FPRINTF(ASCERR, "logical relation term type not recognized\n");
595 return 0;
596 }
597 }
598
599
600 /* For finding the value defined for the tolerance in a SATISFIED term.
601 * The relation instance in the satisfied term must be that given by
602 * the argument condinst
603 */
604
605 int FindTolInSatTermOfLogRel(struct Instance *lrelinst,
606 struct Instance *condinst, double *tolerance)
607 {
608 int found;
609 glob_lrel = NULL;
610
611 if( lrelinst == NULL ) {
612 FPRINTF(ASCERR, "error in FindTolInSatTermOfLogRel: null instance\n");
613 return 1;
614 }
615
616 if( InstanceKind(lrelinst) != LREL_INST ) {
617 FPRINTF(ASCERR, "error in FindTolInSatTermOfLogRel: not logrelation\n");
618 return 1;
619 }
620
621 glob_lrel = (struct logrelation *)GetInstanceLogRel(lrelinst);
622
623 if( glob_lrel == NULL ) {
624 FPRINTF(ASCERR, "error in FindTolInSatTermOfLogRel: null logrelation\n");
625 return 1;
626 }
627
628 if(Infix_Log_LhsSide(glob_lrel) != NULL) {
629 found = FindTolInLogRelBranch(Infix_Log_LhsSide(glob_lrel),condinst,
630 tolerance);
631 if (found) {
632 glob_lrel = NULL;
633 return 0;
634 }
635 } else {
636 glob_lrel = NULL;
637 return 1;
638 }
639
640 if(Infix_Log_RhsSide(glob_lrel) != NULL) {
641 found= FindTolInLogRelBranch(Infix_Log_RhsSide(glob_lrel),condinst,
642 tolerance);
643 if (found) {
644 glob_lrel = NULL;
645 return 0;
646 } else {
647 glob_lrel = NULL;
648 return 1;
649 }
650 } else {
651 glob_lrel = NULL;
652 return 1;
653 }
654 }
655
656
657 /* Note that ANY function calling LogRelBranchEvaluator should set
658 * glob_lrel to point at the logical relation being evaluated.
659 * The calling function should also set glob_lrel = NULL when it
660 * is done.
661 */
662
663 static int LogRelBranchEvaluator(struct logrel_term *term, int perturb,
664 struct gl_list_t *instances)
665 {
666 assert(term != NULL);
667 switch(LogRelTermType(term)) {
668 case e_var:
669 return LogTermBoolVar(glob_lrel,term);
670 case e_int:
671 return LogTermIntegerBoolValue(term);
672 case e_boolean:
673 return LogTermBoolean(term);
674 case e_satisfied:
675 return LogTermSatisfied(glob_lrel,term,perturb,instances);
676 case e_and:
677 return (LogRelBranchEvaluator(LogTermBinLeft(term),perturb,instances) &&
678 LogRelBranchEvaluator(LogTermBinRight(term),perturb,instances));
679 case e_or:
680 return (LogRelBranchEvaluator(LogTermBinLeft(term),perturb,instances) ||
681 LogRelBranchEvaluator(LogTermBinRight(term),perturb,instances));
682 case e_not:
683 return (!LogRelBranchEvaluator(LogTermBinLeft(term),perturb,instances));
684 /* return (LogRelBranchEvaluator(LogTermBinLeft(term),perturb,instances)
685 ? 0 : 1); */
686 default:
687 FPRINTF(ASCERR, "error in LogRelBranchEvaluator routine\n");
688 FPRINTF(ASCERR, "logical relation term type not recognized\n");
689 return 0;
690 }
691 }
692
693 /* LogRelEvaluatePostfixBranch
694 * This function is passed a logical relation pointer, lrel, a pointer,
695 * pos, to a position in the postfix version of the logical relation
696 * (0<=pos<length), and a flag, lhs, telling whether we are interested
697 * in the left(=1) or right(=0) side of the logical relation.
698 * This function will tranverse and evaluate the subtree rooted at pos
699 * and will return the value as an integer (0,1).
700 * To do its evaluation, this function goes backwards through
701 * the postfix representation of logical relation and calls itself at each
702 * node--creating a stack of function calls.
703 * NOTE: This function changes the value of pos--- to the position of
704 * the deepest leaf visited
705 */
706 static int
707 LogRelEvaluatePostfixBranch(CONST struct logrelation *lrel,
708 unsigned long *pos,
709 int lhs, int perturb,
710 struct gl_list_t *instances)
711 {
712 CONST struct logrel_term *term; /* the current term */
713 int b; /* temporary value */
714
715 term = NewLogRelTerm(lrel,*pos,lhs);
716 assert(term != NULL);
717 switch( LogRelTermType(term) ) {
718 case e_int:
719 return LogTermIntegerBoolValue(term);
720 case e_var:
721 return LogTermBoolVar(lrel, term);
722 case e_boolean:
723 return LogTermBoolean(term);
724 case e_satisfied:
725 return LogTermSatisfied(lrel,term,perturb,instances);
726 case e_and:
727 (*pos)--;
728 b = LogRelEvaluatePostfixBranch(lrel,pos,lhs,perturb,instances);
729 /* b==right-side of 'AND' */
730 (*pos)--;
731 return (LogRelEvaluatePostfixBranch(lrel,pos,lhs,perturb,instances) && b);
732 case e_or:
733 (*pos)--;
734 b = LogRelEvaluatePostfixBranch(lrel,pos,lhs,perturb,instances);
735 /* b==right-side of 'OR' */
736 (*pos)--;
737 return (LogRelEvaluatePostfixBranch(lrel,pos,lhs,perturb,instances) || b);
738 case e_not:
739 (*pos)--;
740 return (!LogRelEvaluatePostfixBranch(lrel,pos,lhs,perturb,instances));
741 /* return (LogRelEvaluatePostfixBranch(lrel,pos,lhs,perturb,instances))
742 ? 0 : 1); */
743 default:
744 Asc_Panic(2, NULL,
745 "Don't know this type of logical relation term\n"
746 "in function LogRelEvaluatePostfixBranch\n");
747
748 }
749 }
750
751
752 /* LogRelEvaluateResidualPostfix
753 * Yet another function for calculating the residual of a logical relation.
754 * This function also uses the postfix version of the logical relations,
755 * but it manages a stack(array) of ints and calculates the residual in this
756 * stack; therefore the function is not recursive. If the funtion
757 * cannot allocate memory for its stack, it returns 0, so there is
758 * currently no way of knowing if this function failed.
759 */
760 static int
761 LogRelEvaluateResidualPostfix(CONST struct logrelation *lrel, int perturb,
762 struct gl_list_t *instances)
763 {
764 unsigned long t; /* the current term in the logical relation lrel */
765 int lhs; /* looking at left(=1) or right(=0) hand side */
766 int *res_stack; /* the stack we use for evaluating the residual */
767 long s = -1; /* the top position in the stacks */
768 unsigned long length_lhs, length_rhs;
769 CONST struct logrel_term *term;
770 enum Expr_enum lrelop;
771
772 length_lhs = LogRelLength(lrel,1);
773 length_rhs = LogRelLength(lrel,0);
774 if( (length_lhs+length_rhs) == 0 ) return 0;
775 lrelop = LogRelRelop(lrel);
776 /* create the stacks */
777 res_stack = tmpalloc_array((1+MAX(length_lhs,length_rhs)),int);
778 if( res_stack == NULL ) return 0;
779
780 lhs = 1;
781 t = 0;
782 while (1) {
783 if( lhs && (t >= length_lhs) ) {
784 /* finished processing left hand side, switch to right if it exists */
785 if( length_rhs ) {
786 lhs = t = 0;
787 }
788 else {
789 /* do not need to check for s>=0, since we know that
790 * (length_lhs+length_rhs>0) and that (length_rhs==0), the
791 * length_lhs must be > 0, thus s>=0
792 */
793 return 0;
794 }
795 }
796 else if( (!lhs) && (t >= length_rhs) ) {
797 /* finished processing right hand side */
798 if( length_lhs ) {
799 /* we know length_lhs and length_rhs are both > 0, since if
800 * length_rhs == 0, we would have exited above.
801 */
802 if (lrelop == e_boolean_eq) {
803 if (res_stack[s-1] == res_stack[s]) {
804 return 1;
805 }
806 else {
807 return 0;
808 }
809 }
810 else if (lrelop == e_boolean_neq) {
811 if (res_stack[s-1] != res_stack[s]) {
812 return 1;
813 }
814 else {
815 return 0;
816 }
817 } else {
818 FPRINTF(ASCERR, "error in LogRelEvaluateResidualPostfix:\n");
819 FPRINTF(ASCERR, "wrong logical relation operator \n");
820 return 0;
821 }
822 }
823 else {
824 /* do not need to check for s>=0, since we know that
825 * (length_lhs+length_rhs>0) and that (length_lhs==0), the
826 * length_rhs must be > 0, thus s>=0
827 */
828 return 0;
829 }
830 }
831
832 term = NewLogRelTerm(lrel,t++,lhs);
833 switch( LogRelTermType(term) ) {
834 case e_boolean:
835 s++;
836 res_stack[s] = LogTermBoolean(term);
837 break;
838 case e_satisfied:
839 s++;
840 res_stack[s] = LogTermSatisfied(lrel,term,perturb,instances);
841 break;
842 case e_int:
843 s++;
844 res_stack[s] = LogTermIntegerBoolValue(term);
845 break;
846 case e_var:
847 s++;
848 res_stack[s] = LogTermBoolVar(lrel,term);
849 break;
850 case e_and:
851 res_stack[s-1] = (res_stack[s-1] && res_stack[s]);
852 s--;
853 break;
854 case e_or:
855 res_stack[s-1] = ( res_stack[s-1] || res_stack[s]);
856 s--;
857 break;
858 case e_uminus:
859 res_stack[s] = ( !res_stack[s] );
860 break;
861 default:
862 Asc_Panic(2, NULL,
863 "Don't know this type of logical relation term\n"
864 "in function LogRelEvaluateResidualPostfix\n");
865 break;
866 }
867 }
868 }
869
870 /*
871 * CALCULATION ROUTINES
872 */
873
874
875 int
876 LogRelCalcResidualPostfix(struct Instance *i, int *res, int perturb,
877 struct gl_list_t *instances)
878 {
879 struct logrelation *lrel;
880 enum Expr_enum lrelop;
881 unsigned long length_lhs, length_rhs;
882
883 #ifndef NDEBUG
884 if( i == NULL ) {
885 FPRINTF(ASCERR, "error in LogRelCalcResidualPostfix: null instance\n");
886 return 1;
887 }
888 if (res == NULL){
889 FPRINTF(ASCERR,"error in LogRelCalcResidualPostfix: null ptr\n");
890 return 1;
891 }
892 if( InstanceKind(i) != LREL_INST ) {
893 FPRINTF(ASCERR, "error in LogRelCalcResidualPostfix: not logrelation\n");
894 return 1;
895 }
896 #endif
897 lrel = (struct logrelation *)GetInstanceLogRel(i);
898 if( lrel == NULL ) {
899 FPRINTF(ASCERR, "error in LogRelCalcResidualPostfix: null logrelation\n");
900 return 1;
901 }
902
903 lrelop = LogRelRelop(lrel);
904 length_lhs = LogRelLength(lrel,1);
905 length_rhs = LogRelLength(lrel,0);
906
907 if( length_lhs > 0 ) {
908 length_lhs--;
909 *res = LogRelEvaluatePostfixBranch(lrel,&length_lhs,1,perturb,instances);
910 }
911 else {
912 *res = 0;
913 }
914
915 if( lrelop == e_boolean_eq ) {
916 if( length_rhs > 0 ) {
917 length_rhs--;
918 if (*res == LogRelEvaluatePostfixBranch(lrel, &length_rhs,
919 0,perturb,instances)) {
920 *res = 1;
921 }
922 else {
923 *res = 0;
924 }
925 }
926 return 0;
927 }
928 else {
929 if(lrelop == e_boolean_neq) {
930 if( length_rhs > 0 ) {
931 length_rhs--;
932 if (*res != LogRelEvaluatePostfixBranch(lrel,&length_rhs,
933 0,perturb,instances)) {
934 *res = 1;
935 }
936 else {
937 *res = 0;
938 }
939 }
940 return 0;
941 }
942 else {
943 FPRINTF(ASCERR, "error in RelationCalcResidualPostfix:\n");
944 FPRINTF(ASCERR, "wrong logical relation operator \n");
945 return 1;
946 }
947 }
948 }
949
950 int
951 LogRelCalcResidualInfix(struct Instance *i, int *res, int perturb,
952 struct gl_list_t *instances)
953 {
954 enum Expr_enum lrelop;
955 glob_lrel = NULL;
956
957 #ifndef NDEBUG
958 if( i == NULL ) {
959 FPRINTF(ASCERR, "error in LogRelCalcResidualInfix: null instance\n");
960 return 1;
961 }
962 if (res == NULL){
963 FPRINTF(ASCERR,"error in LogRelCalcResidualInfix: null ptr\n");
964 return 1;
965 }
966 if( InstanceKind(i) != LREL_INST ) {
967 FPRINTF(ASCERR, "error in LogRelCalcResidualInfix: not logrelation\n");
968 return 1;
969 }
970 #endif
971 glob_lrel = (struct logrelation *)GetInstanceLogRel(i);
972 if( glob_lrel == NULL ) {
973 FPRINTF(ASCERR, "error in LogRelCalcResidualInfix: null logrelation\n");
974 return 1;
975 }
976 lrelop = LogRelRelop(glob_lrel);
977
978 if(Infix_Log_LhsSide(glob_lrel) != NULL) {
979 *res = LogRelBranchEvaluator(Infix_Log_LhsSide(glob_lrel),
980 perturb,instances);
981 } else {
982 *res = 0;
983 }
984
985 if( lrelop == e_boolean_eq ) {
986 if(Infix_Log_RhsSide(glob_lrel) != NULL) {
987 if (*res == LogRelBranchEvaluator(Infix_Log_RhsSide(glob_lrel),
988 perturb,instances)){
989 *res = 1;
990 }
991 else {
992 *res = 0;
993 }
994 }
995 glob_lrel = NULL;
996 return 0;
997 }
998 else if (lrelop == e_boolean_neq) {
999 if(Infix_Log_RhsSide(glob_lrel) != NULL) {
1000 if (*res != LogRelBranchEvaluator(Infix_Log_RhsSide(glob_lrel),
1001 perturb,instances)){
1002 *res = 1;
1003 }
1004 else {
1005 *res = 0;
1006 }
1007 }
1008 glob_lrel = NULL;
1009 return 0;
1010 } else {
1011 FPRINTF(ASCERR, "error in LogRelCalcResidualInfix:\n");
1012 FPRINTF(ASCERR, "wrong logical relation operator \n");
1013 glob_lrel = NULL;
1014 return 1;
1015 }
1016 }
1017
1018
1019 /* LogRelCalcResidualPostfix2
1020 * Yes, yet another function to calculate the logical residual
1021 * It is not used anywhere. It does take in account the perturb
1022 * flag of the other routine calculations.
1023 */
1024 int
1025 LogRelCalcResidualPostfix2(struct Instance *i,int *res, int perturb,
1026 struct gl_list_t *instances)
1027 {
1028 struct logrelation *lrel;
1029
1030 #ifndef NDEBUG
1031 if( i == NULL ) {
1032 FPRINTF(ASCERR, "error in LogRelCalcResidualPostfix2: null instance\n");
1033 return 1;
1034 }
1035 if( res == NULL ) {
1036 FPRINTF(ASCERR, "error in LogRelCalcResidualPostfix2: null ptr\n");
1037 return 1;
1038 }
1039 if( InstanceKind(i) != LREL_INST ) {
1040 FPRINTF(ASCERR, "error in LogRelCalcResidualPostfix2: not logrelation\n");
1041 return 1;
1042 }
1043 #endif
1044 lrel = (struct logrelation *)GetInstanceLogRel(i);
1045 if( lrel == NULL ) {
1046 FPRINTF(ASCERR, "error in LogRelCalcResidualPostfix2: null logrelation\n");
1047 return 1;
1048 }
1049
1050 *res = LogRelEvaluateResidualPostfix(lrel,perturb,instances);
1051 return 0;
1052 }
1053
1054
1055 /**
1056 *** The following functions support LogRelFindBoolValues which
1057 *** is the compiler implementation of DirectSolve for Logical
1058 *** relations.
1059 *** These functions can be catagorized as follows:
1060 *** Memory Management and Copying functions:
1061 *** LogRelCreateTmp, LogRelDestroyTmp, LogRelTmpCopySide,
1062 *** LogRelTmpTokenCopy, append_bool_soln
1063 *** Eternal Function:
1064 *** LogRelFindBoolValues
1065 **/
1066
1067 /*************************************************************************\
1068 Memory Management and Copying Functions
1069 \*************************************************************************/
1070
1071 /*
1072 * structure dynamically allocated/reallocated to store the number of
1073 * boolean solutions
1074 */
1075
1076 struct ds_boolsol_list {
1077 int length,capacity;
1078 int *bool_soln;
1079 };
1080
1081
1082 #define alloc_bool_array(nbools,type) ((nbools) > 0 ? ASC_NEW_ARRAY(type,nbools) : NULL)
1083 #define copy_bool_value(from,too,nvalues) \
1084 asc_memcpy((from),(too),(nvalues)*sizeof(int))
1085
1086 /*
1087 * Appends a case_number onto the list
1088 */
1089 static void append_bool_soln( struct ds_boolsol_list *cl, int bool_soln)
1090 {
1091 if( cl->length == cl->capacity ) {
1092 int newcap;
1093 int *newlist;
1094 newcap = cl->capacity + 10;
1095 newlist = alloc_bool_array(newcap,int);
1096 copy_bool_value((char *)cl->bool_soln,(char *)newlist,cl->length);
1097 if( cl->bool_soln != NULL )
1098 ascfree(cl->bool_soln);
1099 cl->bool_soln = newlist;
1100 cl->capacity = newcap;
1101 }
1102 cl->bool_soln[cl->length++] = bool_soln;
1103 }
1104
1105
1106 /**
1107 *** LogRelCreateTmp creates a struct logrelation
1108 *** and passes back a pointer to the logrelation. The lengths of
1109 *** the right and left sides (lhslen and rhslen) of the logrelation
1110 *** are supplied by the calling function.
1111 **/
1112 static struct logrelation *LogRelCreateTmp(int lhslen, int rhslen)
1113 {
1114 struct logrelation *lrel;
1115 lrel = CreateLogRelStructure(e_bol_token);
1116 lrel->token.lhs = ASC_NEW_ARRAY(union LogRelTermUnion, lhslen);
1117 lrel->token.rhs = ASC_NEW_ARRAY(union LogRelTermUnion, rhslen);
1118 return lrel;
1119 }
1120
1121 /**
1122 *** LogRelDestroyTmp deallocates a struct logrelation.
1123 *** The calling function should provide a pointer
1124 *** to the logrelation to be destroyed.
1125 **/
1126 static void LogRelDestroyTmp(struct logrelation *lrel)
1127 {
1128 if (!lrel) return;
1129 if (lrel->token.lhs!=NULL) ascfree(lrel->token.lhs);
1130 if (lrel->token.rhs!=NULL) ascfree(lrel->token.rhs);
1131 ascfree((char *)lrel);
1132 }
1133
1134
1135 /*
1136 * We can now just do a memcopy and the infix pointers
1137 * all adjust by the difference between the token
1138 * arrays that the gl_lists are hiding.
1139 * Note, if any turkey ever tries to delete an individual
1140 * token from these gl_lists AND deallocate it,
1141 * they will get a severe headache.
1142 *
1143 * This is a full blown copy and not copy by reference.
1144 * You do not need to remake the infix pointers after
1145 * calling this function.
1146 */
1147 static int LogRelTmpCopySide(union LogRelTermUnion *old, unsigned long len,
1148 union LogRelTermUnion *arr)
1149 {
1150 struct logrel_term *term;
1151 unsigned long c;
1152 long int delta;
1153
1154 if (old==NULL || !len) return 1;
1155 if (arr==NULL) {
1156 FPRINTF(ASCERR,"LogRelTmpCopySide: null LogRelTermUnion :-(.\n");
1157 return 1;
1158 }
1159 memcpy( (VOIDPTR)arr, (VOIDPTR)old, len*sizeof(union LogRelTermUnion));
1160 /*
1161 * Difference in chars between old and arr ptrs. It should be a multiple
1162 * of sizeof(double) but may not be a multiple of sizeof(union RTU).
1163 * Delta may easily be negative.
1164 * Normally, though arr > old.
1165 */
1166 delta = (char *)arr - (char *)old;
1167 #ifdef ADJLOGPTR
1168 #undef ADJLOGPTR
1169 #endif
1170 #define ADJLOGPTR(p) ( (p) = LOGA_TERM((char *)(p)+delta) )
1171 for (c=0;c<len;c++) {
1172 term = LOGA_TERM(&(arr[c]));
1173 switch (term->t) {
1174 /* unary terms */
1175 case e_not:
1176 ADJLOGPTR(LOGU_TERM(term)->left);
1177 break;
1178 /* binary terms */
1179 case e_and:
1180 case e_or:
1181 ADJLOGPTR(LOGB_TERM(term)->left);
1182 ADJLOGPTR(LOGB_TERM(term)->right);
1183 break;
1184 case e_boolean:
1185 case e_var: /* the var number will be correct */
1186 case e_satisfied:
1187 break;
1188 case e_boolean_eq: case e_boolean_neq:
1189 default:
1190 Asc_Panic(2, "LogRelTmpCopySide",
1191 "Unknown term type in LogRelTmpCopySide\n");
1192 }
1193 }
1194 #undef ADJLOGPTR
1195
1196 return 0;
1197 }
1198
1199 static
1200 struct logrelation *LogRelTmpTokenCopy(CONST struct logrelation *src)
1201 {
1202 struct logrelation *result;
1203 long int delta;
1204 assert(src!=NULL);
1205
1206 result = LogRelCreateTmp(src->token.lhs_len,src->token.rhs_len);
1207
1208 if(LogRelTmpCopySide(src->token.lhs,src->token.lhs_len,
1209 result->token.lhs) == 0) {
1210 delta = LOGUNION_TERM(src->token.lhs_term) - src->token.lhs;
1211 result->token.lhs_term = LOGA_TERM(result->token.lhs+delta);
1212 result->token.lhs_len = src->token.lhs_len;
1213 } else {
1214 result->token.lhs_term = NULL;
1215 result->token.lhs_len = 0;
1216 }
1217
1218 if(LogRelTmpCopySide(src->token.rhs,src->token.rhs_len,
1219 result->token.rhs) == 0) {
1220 delta = LOGUNION_TERM(src->token.rhs_term) - src->token.rhs;
1221 result->token.rhs_term = LOGA_TERM(result->token.rhs+delta);
1222 result->token.rhs_len = src->token.rhs_len;
1223 } else {
1224 result->token.rhs_term = NULL;
1225 result->token.rhs_len = 0;
1226 }
1227
1228 result->bvars = src->bvars;
1229 result->satrels = src->satrels;
1230 result->logresidual = src->logresidual;
1231 result->lognominal = src->lognominal;
1232 return result;
1233 }
1234
1235
1236 /*************************************************************************\
1237 External Function
1238 \*************************************************************************/
1239
1240 /**
1241 *** LogRelFindBoolValues WILL find a boolean value if there is one.
1242 *** It returns 1 for success and 0 for failure. In general compiler
1243 *** functions return 0 for success but this function returns 1 for
1244 *** success because success = 1 is the convention on the solver side.
1245 *** A return of -1 indicates a problem such as var not found.
1246 *** If nsolns > 1 then a list of solutions will be returned.
1247 *** For logical equations, at most two values are expected
1248 **/
1249
1250 /* Note we should recycle the memory used for glob_lrel */
1251
1252 int *LogRelFindBoolValues(struct Instance *i, unsigned long *dvarnum,
1253 int *able,int *nsolns, int perturb,
1254 struct gl_list_t *instances)
1255 {
1256 struct logrelation *lrel;
1257 struct ds_boolsol_list soln_list;
1258 CONST struct gl_list_t *list;
1259 int res,status,bvalue;
1260
1261 soln_list.length = soln_list.capacity = 0;
1262 soln_list.bool_soln = NULL;
1263 append_bool_soln(&soln_list,0);
1264
1265 *able = FALSE;
1266 *nsolns = -1; /* nsolns will be -1 for a very unhappy rootfinder */
1267 glob_lrel = NULL;
1268
1269
1270 #ifndef NDEBUG
1271 if( i == NULL ) {
1272 FPRINTF(ASCERR, "error in LogRelFindBoolValues: null instance\n");
1273 glob_lrel = NULL; return NULL;
1274 }
1275 if (able == NULL){
1276 FPRINTF(ASCERR,"error in LogRelFindBoolValues: null int ptr\n");
1277 glob_lrel = NULL; return NULL;
1278 }
1279 if (dvarnum == NULL){
1280 FPRINTF(ASCERR,"error in LogRelFindBoolValues: null dvarnum\n");
1281 glob_lrel = NULL; return NULL;
1282 }
1283 if( InstanceKind(i) != LREL_INST ) {
1284 FPRINTF(ASCERR, "error in LogRelFindBoolValues: not logrelation\n");
1285 glob_lrel = NULL; return NULL;
1286 }
1287 #endif
1288 lrel = (struct logrelation *)GetInstanceLogRel(i);
1289 if( lrel == NULL ) {
1290 FPRINTF(ASCERR, "error in LogRelFindBoolValues: null logrelation\n");
1291 glob_lrel = NULL; return NULL;
1292 }
1293
1294 glob_lrel = LogRelTmpTokenCopy(lrel);
1295 assert(glob_lrel!=NULL);
1296 list = LogRelBoolVarList(glob_lrel);
1297
1298 if(!(*dvarnum >= 1 && *dvarnum <= gl_length(list))){
1299 FPRINTF(ASCERR, "Error in LogRelFindBoolValues: dvar not found\n");
1300 glob_lrel = NULL;
1301 return NULL;
1302 }
1303
1304 /* Current value */
1305 bvalue = GetBooleanAtomValue((struct Instance *)
1306 gl_fetch(LogRelBoolVarList(glob_lrel),*dvarnum));
1307 status = 1;
1308
1309 /* Assign the value TRUE to the boolean */
1310 SetBooleanAtomValue(
1311 (struct Instance *)gl_fetch(LogRelBoolVarList(glob_lrel),*dvarnum),TRUE,0);
1312
1313 /* Check Residual */
1314 status = LogRelCalcResidualPostfix(i,&res,perturb,instances);
1315 if (!status) {
1316 if (res) {
1317 *nsolns = 1;
1318 append_bool_soln(&soln_list,1);
1319 }
1320
1321 /* Assign the value FALSE to the boolean */
1322 SetBooleanAtomValue(
1323 (struct Instance *)gl_fetch(LogRelBoolVarList(glob_lrel),*dvarnum),FALSE,0);
1324
1325 /* Check Residual */
1326 status = LogRelCalcResidualPostfix(i,&res,perturb,instances);
1327
1328 if (!status) {
1329 if (res) {
1330 if ((*nsolns)== 1) {
1331 *nsolns = 2;
1332 } else {
1333 *nsolns = 1;
1334 }
1335 append_bool_soln(&soln_list,0);
1336 }
1337 }
1338 /* Assign original boolean value */
1339 SetBooleanAtomValue(
1340 (struct Instance *)gl_fetch(LogRelBoolVarList(glob_lrel),*dvarnum),bvalue,0);
1341
1342 }else {
1343 *able = FALSE;
1344 LogRelDestroyTmp(glob_lrel);
1345 return soln_list.bool_soln;
1346 }
1347 *able = TRUE;
1348 LogRelDestroyTmp(glob_lrel);
1349 return soln_list.bool_soln;
1350 }
1351
1352
1353 /*
1354 * Temporary Functions for testing direct solve.
1355 * Remove calls from interface.c when this is removed.
1356 */
1357 void PrintDirectBooleanResult(struct Instance *i)
1358 {
1359 struct logrelation *lrel;
1360 int num,status,n,nsoln;
1361 int *soln_list;
1362 unsigned long dvarnum;
1363 CONST struct gl_list_t *list;
1364
1365 if (InstanceKind(i) == LREL_INST) {
1366 lrel = (struct logrelation *)GetInstanceLogRel(i);
1367 list = LogRelBoolVarList(lrel);
1368 for(num = 1; num <= (int)gl_length(list);++num) {
1369 status = -1;
1370 dvarnum = num;
1371 soln_list = LogRelFindBoolValues(i,&(dvarnum),&(status),&(nsoln),0,NULL);
1372 if (nsoln > 0) {
1373 FPRINTF(stderr,"VAR NUMBER %d\n",num);
1374 for(n =1; n<=nsoln;n++) {
1375 FPRINTF(stderr,"SOLUTION = %d\n",soln_list[n]);
1376 }
1377 }
1378 }
1379 }
1380 }
1381
1382 void PrintDirectSolveBooleanSolutions(struct Instance *i)
1383 {
1384 VisitInstanceTree(i,PrintDirectBooleanResult, 0, 0);
1385 }
1386

john.pye@anu.edu.au
ViewVC Help
Powered by ViewVC 1.1.22