node_ptr Wff_make_opnext_times(NodeMgr_ptr nodemgr, node_ptr arg, int x) { nusmv_assert(x >= 0); if (x == 0) return arg; else return Wff_make_opnext(nodemgr, Wff_make_opnext_times(nodemgr, arg, x - 1)); }
/**Function******************************************************************** Synopsis [The private function that does the actual wff2nnf conversion] Description [The private function that does the actual wff2nnf conversion] SideEffects [] SeeAlso [] ******************************************************************************/ static node_ptr w2w_wff_mk_nnf(node_ptr wff, boolean pol) { node_ptr res; /* if reached a Nil branch then end recursion with a Nil node */ if (wff == Nil) return Nil; /* Only temporal operator X (node type OP_NEXT) is legal in LTL wffs. The operator NEXT used in model definition is trapped. */ nusmv_assert(node_get_type(wff) != NEXT); res = w2w_wff2nnf_hash_lookup_entry(wff, pol); if (res != (node_ptr) NULL) return res; switch (node_get_type(wff)) { case TRUEEXP: if (pol) res = Wff_make_truth(); else res = Wff_make_falsity(); /* !1 <-> 0 */ break; case FALSEEXP: if (pol) res = Wff_make_falsity(); else res = Wff_make_truth(); /* !0 <-> 1 */ break; case NOT: /* !(a) <-> (!a) */ /* !(!a) <-> a */ res = w2w_wff_mk_nnf(car(wff), !pol); break; case AND: if (pol) res = Wff_make_and(w2w_wff_mk_nnf(car(wff), true), w2w_wff_mk_nnf(cdr(wff), true)); else { /* !(a & b) <-> (!a | !b) */ res = Wff_make_or(w2w_wff_mk_nnf(car(wff), false), w2w_wff_mk_nnf(cdr(wff), false)); } break; case OR: if (pol) res = Wff_make_or(w2w_wff_mk_nnf(car(wff), true), w2w_wff_mk_nnf(cdr(wff), true)); else { /* !(a | b) <-> (!a & !b) */ res = Wff_make_and(w2w_wff_mk_nnf(car(wff), false), w2w_wff_mk_nnf(cdr(wff), false)); } break; case IMPLIES: if (pol) { /* (a -> b) <-> !(a & !b) <-> (!a | b) */ res = Wff_make_or(w2w_wff_mk_nnf(car(wff), false), w2w_wff_mk_nnf(cdr(wff), true)); } else { /* !(a -> b) <-> (a & !b) */ res = Wff_make_and(w2w_wff_mk_nnf(car(wff), true), w2w_wff_mk_nnf(cdr(wff), false)); } break; case IFF: if (pol) { /* (a <-> b) <-> !(a & !b) & !(b & !a) <-> (!a | b) & (!b | a) */ res = Wff_make_and( Wff_make_or(w2w_wff_mk_nnf(car(wff), false), w2w_wff_mk_nnf(cdr(wff), true)), Wff_make_or(w2w_wff_mk_nnf(car(wff), true), w2w_wff_mk_nnf(cdr(wff), false)) ); } else { /* !(a <-> b) <-> !(!(a & !b) & !(b & !a)) <-> (a & !b) | (b & !a) */ res = Wff_make_or( Wff_make_and(w2w_wff_mk_nnf(car(wff), true), w2w_wff_mk_nnf(cdr(wff), false)), Wff_make_and(w2w_wff_mk_nnf(car(wff), false), w2w_wff_mk_nnf(cdr(wff), true)) ); } break; case XOR: if (pol) { /* (a xor b) <-> (a & !b) | (!a & b) */ res = Wff_make_or( Wff_make_and(w2w_wff_mk_nnf(car(wff), true), w2w_wff_mk_nnf(cdr(wff), false)), Wff_make_and(w2w_wff_mk_nnf(car(wff), false), w2w_wff_mk_nnf(cdr(wff), true)) ); } else { /* !(a xnor b) <-> (a | !b) & (!a | b) */ res = Wff_make_and( Wff_make_or(w2w_wff_mk_nnf(car(wff), true), w2w_wff_mk_nnf(cdr(wff), false)), Wff_make_or(w2w_wff_mk_nnf(car(wff), false), w2w_wff_mk_nnf(cdr(wff), true)) ); } break; case XNOR: if (pol) { /* (a xnor b) <-> (!a | b) & (!b | a) */ res = Wff_make_and( Wff_make_or(w2w_wff_mk_nnf(car(wff), false), w2w_wff_mk_nnf(cdr(wff), true)), Wff_make_or(w2w_wff_mk_nnf(car(wff), true), w2w_wff_mk_nnf(cdr(wff), false)) ); } else { /* !(a xnor b) <-> (a & !b) | (!a & b) */ res = Wff_make_or( Wff_make_and(w2w_wff_mk_nnf(car(wff), true), w2w_wff_mk_nnf(cdr(wff), false)), Wff_make_and(w2w_wff_mk_nnf(car(wff), false), w2w_wff_mk_nnf(cdr(wff), true)) ); } break; case OP_NEXT: /* !X(a) <-> X(!a) */ res = Wff_make_opnext(w2w_wff_mk_nnf(car(wff), pol)); break; case OP_PREC: /* !Y(a) <-> Z(!a) */ if (pol) res = Wff_make_opprec(w2w_wff_mk_nnf(car(wff), pol)); else res = Wff_make_opnotprecnot(w2w_wff_mk_nnf(car(wff), pol)); break; case OP_NOTPRECNOT: /* !Z(a) <-> Y(!a) */ if (pol) res = Wff_make_opnotprecnot(w2w_wff_mk_nnf(car(wff), pol)); else res = Wff_make_opprec(w2w_wff_mk_nnf(car(wff), pol)); break; case OP_GLOBAL: if (pol) res = Wff_make_globally(w2w_wff_mk_nnf(car(wff), pol)); else { /* !G(a) <-> F(!a) */ res = Wff_make_eventually(w2w_wff_mk_nnf(car(wff), pol)); } break; case OP_HISTORICAL: if (pol) res = Wff_make_historically(w2w_wff_mk_nnf(car(wff), pol)); else { /* !H(a) <-> O(!a) */ res = Wff_make_once(w2w_wff_mk_nnf(car(wff), pol)); } break; case OP_FUTURE: if (pol) res = Wff_make_eventually(w2w_wff_mk_nnf(car(wff), pol)); else { /* !F(a) <-> G(!a) */ res = Wff_make_globally(w2w_wff_mk_nnf(car(wff), pol)); } break; case OP_ONCE: if (pol) res = Wff_make_once(w2w_wff_mk_nnf(car(wff), pol)); else { /* !O(a) <-> H(!a) */ res = Wff_make_historically(w2w_wff_mk_nnf(car(wff), pol)); } break; case UNTIL: if (pol) res = Wff_make_until(w2w_wff_mk_nnf(car(wff), pol), w2w_wff_mk_nnf(cdr(wff), pol)); else { /* !(a U b) <-> (!a V !b) */ res = Wff_make_releases(w2w_wff_mk_nnf(car(wff), pol), w2w_wff_mk_nnf(cdr(wff), pol)); } break; case SINCE: if (pol) res = Wff_make_since(w2w_wff_mk_nnf(car(wff), pol), w2w_wff_mk_nnf(cdr(wff), pol)); else { /* !(a S b) <-> (!a T !b) */ res = Wff_make_triggered(w2w_wff_mk_nnf(car(wff), pol), w2w_wff_mk_nnf(cdr(wff), pol)); } break; case RELEASES: if (pol) res = Wff_make_releases(w2w_wff_mk_nnf(car(wff), pol), w2w_wff_mk_nnf(cdr(wff), pol)); else { /* !(a V b) <-> (!a U !b) */ res = Wff_make_until(w2w_wff_mk_nnf(car(wff), pol), w2w_wff_mk_nnf(cdr(wff), pol)); } break; case TRIGGERED: if (pol) res = Wff_make_triggered(w2w_wff_mk_nnf(car(wff), pol), w2w_wff_mk_nnf(cdr(wff), pol)); else { /* !(a T b) <-> (!a S !b) */ res = Wff_make_since(w2w_wff_mk_nnf(car(wff), pol), w2w_wff_mk_nnf(cdr(wff), pol)); } break; case IFTHENELSE: case CASE: { node_ptr nocase_wff = w2w_wff_expand_case(wff); res = w2w_wff_mk_nnf(nocase_wff, pol); break; } case BIT: case DOT: case ARRAY: /* it is a bexp var */ if (pol) res = wff; else res = Wff_make_not(wff); break; case ATOM: case NUMBER: case NUMBER_UNSIGNED_WORD: case NUMBER_SIGNED_WORD: case NUMBER_FRAC: case NUMBER_REAL: case NUMBER_EXP: /* internal format for atoms that should have been previously hidden within DOT and ARRAY */ internal_error("w2w_wff_mk_nnf: unexpected leaf %d\n", node_get_type(wff)); res = (node_ptr) NULL; break; case MOD: internal_error("w2w_wff_mk_nnf: unexpected mod operator\n"); /* stop recursion when a predicate is found */ case LE: case LT: case GE: case GT: case EQUAL: case NOTEQUAL: case SETIN: res = (pol) ? wff : Wff_make_not(wff); break; default: internal_error("w2w_wff_mk_nnf: unexpected TOKEN %d\n", node_get_type(wff)); } if (res != (node_ptr) NULL) { w2w_wff2nnf_hash_insert_entry(wff, pol, res); } return res; }