/**CFile*********************************************************************** FileName [ctlpUtil.c] PackageName [ctlp] Synopsis [Routines for manipulating CTL formulas.] Description [This file contains routines for accessing the fields of the CTL formula data structure, for printing CTL formulas, for reading CTL formulas from a file, and for converting formulas to the existential form.] Remarks [There are two types of conversion routines. One set, for mc and amc, converts a formula to existential normal form, i.e. the AX, AU and AG operators are converted. The other set, used in imc, converts to simple existential form, a form consisting only of E-operators and the boolean operators AND and NOT. Simple existential form is incompatible with the mc debug routines, because these depend on the specific form of the converted formula to decide what the original formula was. In the long run, the existential form should probably go, and the debug routines should be adapted. The only drawback of simple existential form is that the XOR gets expanded into three nontrivial operations, so maybe XOR (or IFF) should be retained. (RB.)] Author [Gary York, Ramin Hojati, Tom Shiple, Adnan Aziz, Yuji Kukimoto, Jae-Young Jang, In-Ho Moon] Copyright [Copyright (c) 1994-1996 The Regents of the Univ. of California. All rights reserved. Permission is hereby granted, without written agreement and without license or royalty fees, to use, copy, modify, and distribute this software and its documentation for any purpose, provided that the above copyright notice and the following two paragraphs appear in all copies of this software. IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.] ******************************************************************************/ #include "ctlpInt.h" #include "errno.h" static char rcsid[] UNUSED = "$Id: ctlpUtil.c,v 1.71 2009/04/11 18:25:53 fabio Exp $"; /*---------------------------------------------------------------------------*/ /* Variable declarations */ /*---------------------------------------------------------------------------*/ /**Variable******************************************************************** Synopsis [Array of CTL formulas (Ctlp_Formula_t) read from a file.] SeeAlso [Ctlp_FormulaArrayFree] ******************************************************************************/ static array_t *globalFormulaArray; static int changeBracket = 1; /* see ctlpInt.h for documentation */ int CtlpGlobalError; Ctlp_Formula_t *CtlpGlobalFormula; st_table *CtlpMacroTable; /*---------------------------------------------------------------------------*/ /* Macro declarations */ /*---------------------------------------------------------------------------*/ /**AutomaticStart*************************************************************/ /*---------------------------------------------------------------------------*/ /* Static function prototypes */ /*---------------------------------------------------------------------------*/ static Ctlp_Formula_t * FormulaCreateWithType(Ctlp_FormulaType type); static int FormulaCompare(const char *key1, const char *key2); static int FormulaHash(char *key, int modulus); static Ctlp_Formula_t * FormulaHashIntoUniqueTable(Ctlp_Formula_t *formula, st_table *uniqueTable); static Ctlp_Formula_t * FormulaConvertToExistentialDAG(Ctlp_Formula_t *formula); static void FormulaConvertToForward(Ctlp_Formula_t *formula, int compareValue); static void FormulaInsertForwardCompareNodes(Ctlp_Formula_t *formula, Ctlp_Formula_t *parent, int compareValue); static int FormulaGetCompareValue(Ctlp_Formula_t *formula); static int FormulaIsConvertible(Ctlp_Formula_t *formula); static Ctlp_Formula_t * ReplaceSimpleFormula(Ctlp_Formula_t *formula); /**AutomaticEnd***************************************************************/ /*---------------------------------------------------------------------------*/ /* Definition of exported functions */ /*---------------------------------------------------------------------------*/ /**Function******************************************************************** Synopsis [Parses a file containing a set of CTL formulas.] Description [Parses a file containing a set of semicolon-ending CTL formulas, and returns an array of Ctlp_Formula_t representing those formulas. If an error is detected while parsing the file, the routine frees any allocated memory and returns NULL.] SideEffects [Manipulates the global variables globalFormulaArray, CtlpGlobalError and CtlpGlobalFormula.] SeeAlso [Ctlp_FormulaArrayFree Ctlp_FormulaPrint] ******************************************************************************/ array_t * Ctlp_FileParseFormulaArray( FILE * fp) { st_generator *stGen; char *name; Ctlp_Formula_t *formula; char *flagValue; /* * Initialize the global variables. */ globalFormulaArray = array_alloc(Ctlp_Formula_t *, 0); CtlpGlobalError = 0; CtlpGlobalFormula = NIL(Ctlp_Formula_t); CtlpMacroTable = st_init_table(strcmp,st_strhash); CtlpFileSetup(fp); /* * Check if changing "[] -> <>" is disabled. */ flagValue = Cmd_FlagReadByName("ctl_change_bracket"); if (flagValue != NIL(char)) { if (strcmp(flagValue, "yes") == 0) changeBracket = 1; else if (strcmp(flagValue, "no") == 0) changeBracket = 0; else { fprintf(vis_stderr, "** ctl error : invalid value %s for ctl_change_bracket[yes/no]. ***\n", flagValue); } } (void)CtlpYyparse(); st_foreach_item(CtlpMacroTable,stGen,&name,&formula){ FREE(name); CtlpFormulaFree(formula); } st_free_table(CtlpMacroTable); /* * Clean up if there was an error, otherwise return the array. */ if (CtlpGlobalError){ Ctlp_FormulaArrayFree(globalFormulaArray); return NIL(array_t); } else { return globalFormulaArray; } } /**Function******************************************************************** Synopsis [Returns formula as a character string.] Description [Returns formula as a character string. All subformulas are delimited by parenthesis. The syntax used is the same as used by the CTL parser. Does nothing if passed a NULL formula.] SideEffects [] ******************************************************************************/ char * Ctlp_FormulaConvertToString( Ctlp_Formula_t * formula) { char *s1 = NIL(char); char *s2 = NIL(char); char *tmpString = NIL(char); char *result; if (formula == NIL(Ctlp_Formula_t)) { return NIL(char); } /* The formula is a leaf. */ if (formula->type == Ctlp_ID_c){ return util_strcat3((char *)(formula->left), "=",(char *)(formula->right)); } /* If the formula is a non-leaf, the function is called recursively */ s1 = Ctlp_FormulaConvertToString(formula->left); s2 = Ctlp_FormulaConvertToString(formula->right); switch(formula->type) { /* * The cases are listed in rough order of their expected frequency. */ case Ctlp_OR_c: tmpString = util_strcat3(s1, " + ",s2); result = util_strcat3("(", tmpString, ")"); break; case Ctlp_AND_c: tmpString = util_strcat3(s1, " * ", s2); result = util_strcat3("(", tmpString, ")"); break; case Ctlp_THEN_c: tmpString = util_strcat3(s1, " -> ", s2); result = util_strcat3("(", tmpString, ")"); break; case Ctlp_XOR_c: tmpString = util_strcat3(s1, " ^ ", s2); result = util_strcat3("(", tmpString, ")"); break; case Ctlp_EQ_c: tmpString = util_strcat3(s1, " <-> ", s2); result = util_strcat3("(", tmpString, ")"); break; case Ctlp_NOT_c: tmpString = util_strcat3("(", s1, ")"); result = util_strcat3("!", tmpString, ""); break; case Ctlp_EX_c: result = util_strcat3("EX(", s1, ")"); FREE(s1); break; case Ctlp_EG_c: result = util_strcat3("EG(", s1, ")"); break; case Ctlp_EF_c: result = util_strcat3("EF(", s1, ")"); break; case Ctlp_EU_c: tmpString = util_strcat3("E(", s1, " U "); result = util_strcat3(tmpString, s2, ")"); break; case Ctlp_AX_c: result = util_strcat3("AX(", s1, ")"); break; case Ctlp_AG_c: result = util_strcat3("AG(", s1, ")"); break; case Ctlp_AF_c: result = util_strcat3("AF(", s1, ")"); break; case Ctlp_AU_c: tmpString = util_strcat3("A(", s1, " U "); result = util_strcat3(tmpString, s2, ")"); break; case Ctlp_TRUE_c: result = util_strsav("TRUE"); break; case Ctlp_FALSE_c: result = util_strsav("FALSE"); break; case Ctlp_Init_c: result = util_strsav("Init"); break; case Ctlp_Cmp_c: if (formula->compareValue == 0) tmpString = util_strcat3("[", s1, "] = "); else tmpString = util_strcat3("[", s1, "] != "); result = util_strcat3(tmpString, s2, ""); break; case Ctlp_FwdU_c: tmpString = util_strcat3("FwdU(", s1, ","); result = util_strcat3(tmpString, s2, ")"); break; case Ctlp_FwdG_c: tmpString = util_strcat3("FwdG(", s1, ","); result = util_strcat3(tmpString, s2, ")"); break; case Ctlp_EY_c: result = util_strcat3("EY(", s1, ")"); break; default: fail("Unexpected type"); } if (s1 != NIL(char)) { FREE(s1); } if (s2 != NIL(char)) { FREE(s2); } if (tmpString != NIL(char)) { FREE(tmpString); } return result; } /**Function******************************************************************** Synopsis [Prints a formula to a file.] Description [Prints a formula to a file. All subformulas are delimited by parenthesis. The syntax used is the same as used by the CTL parser. Does nothing if passed a NULL formula.] SideEffects [] ******************************************************************************/ void Ctlp_FormulaPrint( FILE * fp, Ctlp_Formula_t * formula) { char *tmpString; if (formula == NIL(Ctlp_Formula_t)) { return; } tmpString = Ctlp_FormulaConvertToString(formula); (void) fprintf(fp, "%s", tmpString); FREE(tmpString); } /**Function******************************************************************** Synopsis [Gets the type of a formula.] Description [Gets the type of a formula. See ctlp.h for all the types. It is an error to call this function on a NULL formula.] SideEffects [] SeeAlso [] ******************************************************************************/ Ctlp_FormulaType Ctlp_FormulaReadType( Ctlp_Formula_t * formula) { assert( formula != NIL(Ctlp_Formula_t) ); return (formula->type); } #if 0 boolean Ctlp_FormulaReadEvenNegations( Ctlp_Formula_t * formula) { assert(formula != NIL(Ctlp_Formula_t)); return (formula->even_negations); } #endif /**Function******************************************************************** Synopsis [Gets the compare value of a formula.] Description [Gets the compare value of a formula. It is an error to call this function on a NULL formula.] SideEffects [] SeeAlso [] ******************************************************************************/ int Ctlp_FormulaReadCompareValue( Ctlp_Formula_t * formula) { int value; assert( formula != NIL(Ctlp_Formula_t)); value = formula->compareValue; return (value); } /**Function******************************************************************** Synopsis [Reads the variable name of a leaf formula.] Description [Reads the variable name of a leaf formula. It is an error to call this function on a non-leaf formula.] SideEffects [] ******************************************************************************/ char * Ctlp_FormulaReadVariableName( Ctlp_Formula_t * formula) { if (formula->type != Ctlp_ID_c){ fail("Ctlp_FormulaReadVariableName() was called on a non-leaf formula."); } return ((char *)(formula->left)); } /**Function******************************************************************** Synopsis [Reads the value name of a leaf formula.] Description [Reads the value name of a leaf formula. It is an error to call this function on a non-leaf formula.] SideEffects [] ******************************************************************************/ char * Ctlp_FormulaReadValueName( Ctlp_Formula_t * formula) { if (formula->type != Ctlp_ID_c){ fail("Ctlp_FormulaReadValueName() was called on a non-leaf formula."); } return ((char *)(formula->right)); } /**Function******************************************************************** Synopsis [Gets the left child of a formula.] Description [Gets the left child of a formula. User must not free this formula. If a formula is a leaf formula, NIL(Ctlp_Formula_t) is returned.] SideEffects [] SeeAlso [Ctlp_FormulaReadRightChild] ******************************************************************************/ Ctlp_Formula_t * Ctlp_FormulaReadLeftChild( Ctlp_Formula_t * formula) { if (formula->type != Ctlp_ID_c){ return (formula->left); } return NIL(Ctlp_Formula_t); } /**Function******************************************************************** Synopsis [Gets the right child of a formula.] Description [Gets the right child of a formula. User must not free this formula. If a formula is a leaf formula, NIL(Ctlp_Formula_t) is returned.] SideEffects [] SeeAlso [Ctlp_FormulaReadLeftChild] ******************************************************************************/ Ctlp_Formula_t * Ctlp_FormulaReadRightChild( Ctlp_Formula_t * formula) { if (formula->type != Ctlp_ID_c){ return (formula->right); } return NIL(Ctlp_Formula_t); } /**Function******************************************************************** Synopsis [Gets a copy of the set of states for which this formula is true.] Description [Gets a copy of the MDD representing the set of states for which this formula is true. It is the user's responsibility to free this MDD. If the set of states has not yet been computed, then a NULL mdd_t is returned. It is an error to call this function on a NULL formula.] SideEffects [] SeeAlso [Ctlp_FormulaSetStates] ******************************************************************************/ mdd_t * Ctlp_FormulaObtainStates( Ctlp_Formula_t * formula) { assert(formula != NIL(Ctlp_Formula_t)); if (formula->states == NIL(mdd_t) || formula->latest == Ctlp_Incomparable_c) { return NIL(mdd_t); } else { return mdd_dup(formula->states); } } /**Function******************************************************************** Synopsis [Stores the set of states with the formula.] Description [Stores the MDD with the formula (a copy is not made, and hence, the caller should not later free this MDD). This MDD is intended to represent the set of states for which the formula is true. It is an error to call this function on a NULL formula.] SideEffects [] SeeAlso [Ctlp_FormulaObtainStates] ******************************************************************************/ void Ctlp_FormulaSetStates( Ctlp_Formula_t * formula, mdd_t * states) { assert(formula != NIL(Ctlp_Formula_t)); /* RB: added the next two lines. Given the Description, this was a bug */ if(formula->states != NIL(mdd_t)) mdd_free(formula->states); formula->states = states; formula->latest = Ctlp_Exact_c; } /**Function******************************************************************** Synopsis [Gets (a copy of) the latest approximation of the satisfying set] Description [Gets the satisfying set or an approximation of it. The most recently computed approximation is returned. If the exact set is available, it will return that, because it is never superseded. If neither exact nor approximate satisfying set is available, or approx is Ctlp_Incomparable_c, it fails.] SideEffects [] SeeAlso [Ctlp_FormulaSetApproxStates] ******************************************************************************/ mdd_t * Ctlp_FormulaObtainLatestApprox( Ctlp_Formula_t *formula) { if (formula->latest == Ctlp_Exact_c) return mdd_dup(formula->states); if (formula->latest == Ctlp_Overapprox_c) return mdd_dup(formula->overapprox); if (formula->latest == Ctlp_Underapprox_c) return mdd_dup(formula->underapprox); if (formula->latest == Ctlp_Incomparable_c) return mdd_dup(formula->states); assert(0); /* we should never get here */ return NIL(mdd_t); } /**Function******************************************************************** Synopsis [Gets (a copy of) an approximation of the satisfying set] Description [Gets the required approximation of the satisfying set. If the exact set is available, it will return that. If neither is available, or approx is Ctlp_Incomparable_c, it will return NULL.] SideEffects [] SeeAlso [Ctlp_FormulaSetApproxStates] ******************************************************************************/ mdd_t * Ctlp_FormulaObtainApproxStates( Ctlp_Formula_t *formula, Ctlp_Approx_t approx) { if(approx == Ctlp_Incomparable_c) return NIL(mdd_t); if (formula->states != NIL(mdd_t)) return mdd_dup(formula->states); if(approx == Ctlp_Exact_c) return NIL(mdd_t); if(approx == Ctlp_Overapprox_c){ if(formula->overapprox == NIL(mdd_t)) return NIL(mdd_t); else return mdd_dup(formula->overapprox); } if(approx == Ctlp_Underapprox_c){ if(formula->underapprox == NIL(mdd_t)) return NIL(mdd_t); else return mdd_dup(formula->underapprox); } assert(0); /* we should never get here */ return NIL(mdd_t); } /**Function******************************************************************** Synopsis [Stores (an approximation of) the set of states with the formula.] Description [Sets the set of states or an under or overapproximation thereof, depending on the approx flag. If there is already an under or overapproximation, it is overwritten. If the exact set is given, the approx fields are cleared. Setting an incomparable approximation results in no action being taken. An approximation does not replace the exact set. A copy of the mdd is not made, so the caller should not free it.] SideEffects [] SeeAlso [Ctlp_FormulaObtainApproxStates Ctlp_FormulaObtainLatestApprox] ******************************************************************************/ void Ctlp_FormulaSetApproxStates( Ctlp_Formula_t * formula, mdd_t * states, Ctlp_Approx_t approx) { if (formula->latest == Ctlp_Exact_c) { mdd_free(states); return; } formula->latest = approx; if (approx == Ctlp_Exact_c) { if (formula->states != NIL(mdd_t)) mdd_free(formula->states); formula->states = states; if (formula->underapprox != NIL(mdd_t)) { mdd_free(formula->underapprox); formula->underapprox = NIL(mdd_t); } if (formula->overapprox != NIL(mdd_t)) { mdd_free(formula->overapprox); formula->overapprox = NIL(mdd_t); } return; } if (approx == Ctlp_Underapprox_c) { /* you could perform a union instead, but typical use will have monotonically increasing underapproximations */ if(formula->underapprox != NIL(mdd_t)) mdd_free(formula->underapprox); formula->underapprox = states; } if (approx == Ctlp_Overapprox_c) { /* you could perform an intersection instead */ if (formula->overapprox != NIL(mdd_t)) mdd_free(formula->overapprox); formula->overapprox = states; } /* This case is possible; for instance when both children of an implication * with (All, S) condition are underapproximated. We may lose some states * from the left if they are not in S. These cause an overapproximation. * We may also lose some states from the right. These cause an * underapproximation. When the two effects are combined, we get something * incomparable, yet sufficient to produce the exact result, because it is * accurate over S. */ if (approx == Ctlp_Incomparable_c) { if (formula->states != NIL(mdd_t)) mdd_free(formula->states); formula->states = states; } return; } /**Function******************************************************************** Synopsis [Sets the debug information of a formula.] Description [Sets the debug information of a CTL formula. The data is uninterpreted. FreeFn is a pointer to a function that takes a formula as input and returns void. FreeFn should free all the memory associated with the debug data; it is called when this formula is freed.] SideEffects [] SeeAlso [Ctlp_FormulaReadDebugData] ******************************************************************************/ void Ctlp_FormulaSetDbgInfo( Ctlp_Formula_t * formula, void *data, Ctlp_DbgInfoFreeFn freeFn) { if (formula->dbgInfo.data != NIL(void)){ assert(formula->dbgInfo.freeFn != NULL); (*formula->dbgInfo.freeFn)(formula); } formula->dbgInfo.data = data; formula->dbgInfo.freeFn = freeFn; } /**Function******************************************************************** Synopsis [Returns the debug data associated with a formula.] Description [Returns the debug data associated with a formula. These data are uninterpreted by the ctlp package.] SideEffects [] SeeAlso [Ctlp_FormulaSetDbgInfo] ******************************************************************************/ void * Ctlp_FormulaReadDebugData( Ctlp_Formula_t * formula) { return formula->dbgInfo.data; } /**Function******************************************************************** Synopsis [Returns TRUE if formula was converted, else FALSE.] from AX/AG/AU/AF] Description [Returns TRUE if formula was converted from a formula of type AG, AX, AU, AF, or EF via a call to Ctlp_FormulaConvertToExistentialFormTree or Ctlp_FormulaConvertToExistentialFormDAG. Otherwise, returns FALSE.] SideEffects [] ******************************************************************************/ boolean Ctlp_FormulaTestIsConverted( Ctlp_Formula_t * formula) { return formula->dbgInfo.convertedFlag; } /**Function******************************************************************** Synopsis [Returns TRUE if formula contains no path quantifiers.] Description [Test if a CTL formula has any path quantifiers in it; if so return false, else true. For a CTL formula, being quantifier-free and being propositional are equivalent.] SideEffects [] ******************************************************************************/ boolean Ctlp_FormulaTestIsQuantifierFree( Ctlp_Formula_t *formula) { boolean lCheck; boolean rCheck; Ctlp_Formula_t *leftChild; Ctlp_Formula_t *rightChild; Ctlp_FormulaType type; if ( formula == NIL( Ctlp_Formula_t ) ) { return TRUE; } type = Ctlp_FormulaReadType( formula ); if ( ( type == Ctlp_ID_c ) || ( type == Ctlp_TRUE_c ) || ( type == Ctlp_FALSE_c ) ) { return TRUE; } if ( ( type != Ctlp_OR_c ) && ( type != Ctlp_AND_c ) && ( type != Ctlp_NOT_c ) && ( type != Ctlp_THEN_c ) && ( type != Ctlp_XOR_c ) && ( type != Ctlp_EQ_c ) ) { return FALSE; } leftChild = Ctlp_FormulaReadLeftChild( formula ); lCheck = Ctlp_FormulaTestIsQuantifierFree( leftChild ); if (lCheck == FALSE) return FALSE; rightChild = Ctlp_FormulaReadRightChild( formula ); rCheck = Ctlp_FormulaTestIsQuantifierFree( rightChild ); return rCheck; } /**Function******************************************************************** Synopsis [Annotates the each node in parse tree with its negation parity.] Description [This function must be called at the top level with parity = Ctlp_Even_c. It will then annotate each node with its parity. A node in a formula with sharing may have both parities and a descendant of a XOR or EQ node will have both. Only backward CTL formulae are considered.] SideEffects [changes the negation_parity fields of all nodes in the formula] ******************************************************************************/ void Ctlp_FormulaNegations( Ctlp_Formula_t * formula, Ctlp_Parity_t parity) { Ctlp_FormulaType formulaType; Ctlp_Formula_t *leftChild; Ctlp_Formula_t *rightChild; Ctlp_Parity_t newparity; assert(formula != NIL(Ctlp_Formula_t)); if (formula->negation_parity == parity) return; /* already done */ if (formula->negation_parity != Ctlp_NoParity_c) parity = Ctlp_EvenOdd_c; /* reconverging paths with different parity */ formula->negation_parity = parity; formulaType = Ctlp_FormulaReadType(formula); leftChild = Ctlp_FormulaReadLeftChild(formula); rightChild = Ctlp_FormulaReadRightChild(formula); switch (formulaType) { case Ctlp_AX_c: case Ctlp_AG_c: case Ctlp_AF_c: case Ctlp_EX_c: case Ctlp_EG_c: case Ctlp_EF_c: Ctlp_FormulaNegations(leftChild,parity); break; case Ctlp_AU_c: case Ctlp_EU_c: case Ctlp_OR_c: case Ctlp_AND_c: Ctlp_FormulaNegations(leftChild,parity); Ctlp_FormulaNegations(rightChild,parity); break; case Ctlp_NOT_c: if (parity == Ctlp_Even_c) newparity = Ctlp_Odd_c; else if (parity == Ctlp_Odd_c) newparity = Ctlp_Even_c; else newparity = Ctlp_EvenOdd_c; Ctlp_FormulaNegations(leftChild,newparity); break; case Ctlp_THEN_c: if (parity == Ctlp_Even_c) newparity = Ctlp_Odd_c; else if (parity == Ctlp_Odd_c) newparity = Ctlp_Even_c; else newparity = Ctlp_EvenOdd_c; Ctlp_FormulaNegations(leftChild,newparity); Ctlp_FormulaNegations(rightChild,parity); break; case Ctlp_XOR_c: case Ctlp_EQ_c: Ctlp_FormulaNegations(leftChild,Ctlp_EvenOdd_c); Ctlp_FormulaNegations(rightChild,Ctlp_EvenOdd_c); break; default: break; } } /**Function******************************************************************** Synopsis [Checks whether an ACTL formula is W-ACTL.] Description [Test if the binary operators in an ACTL formula have at least one propositional formula as one of the operands. If not return Ctlp_NONWACTL_c, else return either Ctlp_WACTLsimple_c for propositional formulae or Ctlp_WACTLstate_c for formulae containing temporal operators. A W-ACTL formula must contain no exitential operators and no forward operators. XOR and EQ are allowed only in propositional subformulae.] SideEffects [none] ******************************************************************************/ Ctlp_FormulaACTLSubClass Ctlp_CheckIfWACTL( Ctlp_Formula_t *formula) { Ctlp_FormulaType formulaType; Ctlp_Formula_t *rightFormula, *leftFormula; Ctlp_FormulaACTLSubClass resultLeft, resultRight; assert(formula != NIL(Ctlp_Formula_t)); if(formula == NIL(Ctlp_Formula_t)) return Ctlp_WACTLsimple_c; formulaType = Ctlp_FormulaReadType(formula); leftFormula = Ctlp_FormulaReadLeftChild(formula); rightFormula = Ctlp_FormulaReadRightChild(formula); /* Depending on the formula type, create result or recur. */ switch (formulaType) { case Ctlp_AX_c: case Ctlp_AG_c: case Ctlp_AF_c: resultLeft = Ctlp_CheckIfWACTL(leftFormula); if (resultLeft == Ctlp_NONWACTL_c) return Ctlp_NONWACTL_c; else return Ctlp_WACTLstate_c; break; case Ctlp_AU_c: resultLeft = Ctlp_CheckIfWACTL(leftFormula); if (resultLeft == Ctlp_NONWACTL_c) return Ctlp_NONWACTL_c; resultRight = Ctlp_CheckIfWACTL(rightFormula); if (resultRight == Ctlp_NONWACTL_c) return Ctlp_NONWACTL_c; if (resultLeft == Ctlp_WACTLsimple_c || resultRight == Ctlp_WACTLsimple_c) return Ctlp_WACTLstate_c; else return Ctlp_NONWACTL_c; break; case Ctlp_OR_c: case Ctlp_AND_c: case Ctlp_THEN_c: resultLeft = Ctlp_CheckIfWACTL(leftFormula); if (resultLeft == Ctlp_NONWACTL_c) { return Ctlp_NONWACTL_c; } else { resultRight = Ctlp_CheckIfWACTL(rightFormula); if (resultRight == Ctlp_WACTLsimple_c) { return resultLeft; } else if (resultLeft == Ctlp_WACTLsimple_c) { return resultRight; } else { return Ctlp_NONWACTL_c; } } break; case Ctlp_NOT_c: resultLeft = Ctlp_CheckIfWACTL(leftFormula); return resultLeft; break; case Ctlp_XOR_c: case Ctlp_EQ_c: resultLeft = Ctlp_CheckIfWACTL(leftFormula); if (resultLeft != Ctlp_WACTLsimple_c) { return Ctlp_NONWACTL_c; } else { resultRight = Ctlp_CheckIfWACTL(rightFormula); if (resultRight == Ctlp_WACTLsimple_c) return Ctlp_WACTLsimple_c; else return Ctlp_NONWACTL_c; } break; case Ctlp_ID_c: case Ctlp_TRUE_c: case Ctlp_FALSE_c: return Ctlp_WACTLsimple_c; break; default: fprintf(vis_stderr, "#Ctlp Result : The formula should be in Universal operators!\n"); return Ctlp_NONWACTL_c; break; } } /* End of Ctlp_CheckTypeOfExistentialFormula */ /**Function******************************************************************** Synopsis [Returns original formula corresponding to converted formula.] SideEffects [] ******************************************************************************/ Ctlp_Formula_t * Ctlp_FormulaReadOriginalFormula( Ctlp_Formula_t * formula) { return formula->dbgInfo.originalFormula; } /**Function******************************************************************** Synopsis [Frees a formula if no other formula refers to it as a sub-formula.] Description [The function decrements the refCount of the formula. As a consequence, if the refCount becomes 0, the formula is freed.] SideEffects [] SeeAlso [CtlpFormulaFree, CtlpDecrementRefCount] ******************************************************************************/ void Ctlp_FormulaFree( Ctlp_Formula_t *formula) { CtlpFormulaDecrementRefCount(formula); } /**Function******************************************************************** Synopsis [Recursively frees states, underapprox and overapprox fields of Ctlp_Formula_t, and the debug data] Description [] SideEffects [] SeeAlso [Ctlp_FormulaFree] ******************************************************************************/ void Ctlp_FlushStates( Ctlp_Formula_t * formula) { if (formula != NIL(Ctlp_Formula_t)) { if (formula->type != Ctlp_ID_c){ if (formula->left != NIL(Ctlp_Formula_t)) { Ctlp_FlushStates(formula->left); } if (formula->right != NIL(Ctlp_Formula_t)) { Ctlp_FlushStates(formula->right); } } if (formula->states != NIL(mdd_t)){ mdd_free(formula->states); formula->states = NIL(mdd_t); } if (formula->underapprox != NIL(mdd_t)){ mdd_free(formula->underapprox); formula->underapprox = NIL(mdd_t); } if (formula->overapprox != NIL(mdd_t)){ mdd_free(formula->overapprox); formula->overapprox = NIL(mdd_t); } if (formula->dbgInfo.data != NIL(void)){ (*formula->dbgInfo.freeFn)(formula); formula->dbgInfo.data = NIL(void); } } } /**Function******************************************************************** Synopsis [Duplicates a CTL formula.] Description [Recursively duplicate a formula. Does nothing if the formula is NIL. Does not copy mdd for states, underapprox, overapprox, dbgInfo, and in general all the information that is used to annotate the formula.] SideEffects [] SeeAlso [] ******************************************************************************/ Ctlp_Formula_t * Ctlp_FormulaDup( Ctlp_Formula_t * formula) { Ctlp_Formula_t *result = NIL(Ctlp_Formula_t); if ( formula == NIL(Ctlp_Formula_t)) { return NIL(Ctlp_Formula_t); } result = ALLOC(Ctlp_Formula_t, 1); result->type = formula->type; result->states = NIL(mdd_t); result->underapprox = NIL(mdd_t); result->overapprox = NIL(mdd_t); result->latest = Ctlp_Incomparable_c; result->Bottomstates = NIL(array_t); result->Topstates = NIL(array_t); result->negation_parity = Ctlp_NoParity_c; result->leaves = formula->leaves == NIL(array_t) ? NIL(array_t) : array_dup(formula->leaves); result->matchfound_top = NIL(array_t); result->matchelement_top = NIL(array_t); result->matchfound_bot = NIL(array_t); result->matchelement_bot = NIL(array_t); result->refCount = 1; result->dbgInfo.data = NIL(void); result->dbgInfo.freeFn = (Ctlp_DbgInfoFreeFn) NULL; result->dbgInfo.convertedFlag = FALSE; result->dbgInfo.originalFormula = NIL(Ctlp_Formula_t); result->top = 0; result->compareValue = 0; if ( formula->type != Ctlp_ID_c ) { result->left = Ctlp_FormulaDup( formula->left ); result->right = Ctlp_FormulaDup( formula->right ); } else { result->left = (Ctlp_Formula_t *) util_strsav((char *)formula->left ); result->right = (Ctlp_Formula_t *) util_strsav((char *)formula->right ); } result->share = 1; result->BotOnionRings = NIL(array_t); result->TopOnionRings = NIL(array_t); return result; } /**Function******************************************************************** Synopsis [Complements a CTL formula.] Description [] SideEffects [] SeeAlso [] ******************************************************************************/ Ctlp_Formula_t * Ctlp_FormulaConverttoComplement( Ctlp_Formula_t * formula) { Ctlp_Formula_t *result; if (formula == NIL(Ctlp_Formula_t)) { return NIL(Ctlp_Formula_t); } result = Ctlp_FormulaCreate(Ctlp_NOT_c,formula,NIL(Ctlp_Formula_t)); CtlpFormulaIncrementRefCount(formula); #if 0 result = FormulaCreateWithType(Ctlp_NOT_c); result->left = FormulaCreateWithType(formula->type); result->left->left = formula->left; result->left->right = formula->right; switch (formula->type) { case Ctlp_ID_c: case Ctlp_TRUE_c: case Ctlp_FALSE_c: case Ctlp_Init_c: break; default: CtlpFormulaIncrementRefCount(formula->left); CtlpFormulaIncrementRefCount(formula->right); break; } #endif return result; } /* Ctlp_FormulaConverttoComplement */ /**Function******************************************************************** Synopsis [Converts AFp to A (TRUE) U p.] Description [] SideEffects [Should be called only for AF formula] SeeAlso [] ******************************************************************************/ Ctlp_Formula_t * Ctlp_FormulaConvertAFtoAU( Ctlp_Formula_t * formula) { Ctlp_Formula_t *result; /* AFf --> (A true U f) */ assert(formula->type == Ctlp_AF_c); result = FormulaCreateWithType(Ctlp_AU_c); result->left = FormulaCreateWithType(Ctlp_TRUE_c); result->right = formula->left; CtlpFormulaIncrementRefCount(formula->left); return result; } /**Function******************************************************************** Synopsis [Converts EFp to p + EX(EFp).] Description [] SideEffects [Should be called only for EF formula] SeeAlso [] ******************************************************************************/ Ctlp_Formula_t * Ctlp_FormulaConvertEFtoOR( Ctlp_Formula_t * formula) { Ctlp_Formula_t *result; /* EFf --> f + EX(EF(f)) */ assert(formula->type == Ctlp_EF_c); result = FormulaCreateWithType(Ctlp_OR_c); result->left = formula->left; result->right = FormulaCreateWithType(Ctlp_EX_c); result->right->left = formula; CtlpFormulaIncrementRefCount(formula->left); CtlpFormulaIncrementRefCount(formula); return result; } /**Function******************************************************************** Synopsis [Converts EpUq to q + p*EX(EpUq).] Description [] SideEffects [Should be called only for EU formula] SeeAlso [] ******************************************************************************/ Ctlp_Formula_t * Ctlp_FormulaConvertEUtoOR( Ctlp_Formula_t * formula) { Ctlp_Formula_t *result; assert(formula->type == Ctlp_EU_c); /* E(f1)U(f2) --> f2 + f1*EX( E(f1)U(f2) ) */ result = FormulaCreateWithType(Ctlp_OR_c); result->left = formula->right; result->right = FormulaCreateWithType(Ctlp_AND_c); result->right->left = formula->left; result->right->right = FormulaCreateWithType(Ctlp_EX_c); result->right->right->left = formula; CtlpFormulaIncrementRefCount(formula->left); CtlpFormulaIncrementRefCount(formula->right); CtlpFormulaIncrementRefCount(formula); return result; } /**Function******************************************************************** Synopsis [Convert p^q to !p*q + p*!q.] Description [] SideEffects [Should be called only for XOR formula] SeeAlso [] ******************************************************************************/ Ctlp_Formula_t * Ctlp_FormulaConvertXORtoOR( Ctlp_Formula_t * formula) { Ctlp_Formula_t *result; assert(formula->type == Ctlp_XOR_c); result = FormulaCreateWithType(Ctlp_OR_c); result->left = FormulaCreateWithType(Ctlp_AND_c); result->right = FormulaCreateWithType(Ctlp_AND_c); result->left->left = Ctlp_FormulaConverttoComplement(formula->left); result->left->right = formula->right; result->right->left = formula->left; result->right->right = Ctlp_FormulaConverttoComplement(formula->right); CtlpFormulaIncrementRefCount(formula->left); CtlpFormulaIncrementRefCount(formula->right); return result; } /**Function******************************************************************** Synopsis [Converts p<->q to p*q + !p*!q.] Description [] SideEffects [Should be called only for EQ formula] SeeAlso [] ******************************************************************************/ Ctlp_Formula_t * Ctlp_FormulaConvertEQtoOR( Ctlp_Formula_t * formula) { Ctlp_Formula_t *result; assert(formula->type == Ctlp_EQ_c); result = FormulaCreateWithType(Ctlp_OR_c); result->left = FormulaCreateWithType(Ctlp_AND_c); result->right = FormulaCreateWithType(Ctlp_AND_c); result->left->left = formula->left; result->left->right = formula->right; result->right->left = Ctlp_FormulaConverttoComplement(formula->left); result->right->right = Ctlp_FormulaConverttoComplement(formula->right); CtlpFormulaIncrementRefCount(formula->left); CtlpFormulaIncrementRefCount(formula->right); return result; } /**Function******************************************************************** Synopsis [Returns formula with a negation pushed down] Description [Returns formula with a negation pushed down. It is assumed that the formula being passsed to it is not a proposition] SideEffects [] ******************************************************************************/ Ctlp_Formula_t * Ctlp_FormulaPushNegation( Ctlp_Formula_t * formula) { Ctlp_Formula_t *result; if (formula == NIL(Ctlp_Formula_t)) { return NIL(Ctlp_Formula_t); } switch(formula->type) { /* * The cases are listed in rough order of their expected frequency. */ case Ctlp_OR_c: /*!(f1 v f2) = !f1 * !f2*/ result = FormulaCreateWithType(Ctlp_AND_c); result->left = Ctlp_FormulaConverttoComplement(formula->left); result->right = Ctlp_FormulaConverttoComplement(formula->right); break; case Ctlp_AND_c: /*!(f1 * f2) = !f1 v !f2*/ result = FormulaCreateWithType(Ctlp_OR_c); result->left = Ctlp_FormulaConverttoComplement(formula->left); result->right = Ctlp_FormulaConverttoComplement(formula->right); break; case Ctlp_THEN_c: /*!(f1 -> f2) = !(!f1 v f2) = f1 * !f2 */ result = FormulaCreateWithType(Ctlp_AND_c); result->left = formula->left; CtlpFormulaIncrementRefCount(formula->left); result->right = Ctlp_FormulaConverttoComplement(formula->right); break; case Ctlp_XOR_c: /*!(f1 ^ f2) = f1 <-> f2*/ result = FormulaCreateWithType(Ctlp_EQ_c); result->left = formula->left; result->right = formula->right; CtlpFormulaIncrementRefCount(formula->left); CtlpFormulaIncrementRefCount(formula->right); break; case Ctlp_EQ_c: /*!(f1 <-> f2) = f1 ^ f2*/ result = FormulaCreateWithType(Ctlp_XOR_c); result->left = formula->left; result->right = formula->right; CtlpFormulaIncrementRefCount(formula->left); CtlpFormulaIncrementRefCount(formula->right); break; case Ctlp_NOT_c:/* !(!f1) = f1*/ result = formula->left; CtlpFormulaIncrementRefCount(formula->left); break; case Ctlp_EX_c:/* !(EX(f1)) = AX(!f1)*/ result = FormulaCreateWithType(Ctlp_AX_c); result->left = Ctlp_FormulaConverttoComplement(formula->left); break; case Ctlp_EG_c: /*!(EG(f1)) = AF(!f1)*/ result = FormulaCreateWithType(Ctlp_AF_c); result->left = Ctlp_FormulaConverttoComplement(formula->left); break; case Ctlp_EF_c: /*!(EF(f1)) = AG(!f1)*/ result = FormulaCreateWithType(Ctlp_AG_c); result->left = Ctlp_FormulaConverttoComplement(formula->left); break; case Ctlp_EU_c: /* !(EpUq) = A(!q)U(!(p+q) + AG(!q))*/ result = FormulaCreateWithType(Ctlp_AU_c); result->left = Ctlp_FormulaConverttoComplement(formula->right); result->right = FormulaCreateWithType(Ctlp_OR_c); result->right->left = FormulaCreateWithType(Ctlp_NOT_c); result->right->left->left = FormulaCreateWithType(Ctlp_OR_c); result->right->left->left->left = formula->left; result->right->left->left->right = formula->right; result->right->right = FormulaCreateWithType(Ctlp_AG_c); result->right->right->left = Ctlp_FormulaConverttoComplement(formula->right); CtlpFormulaIncrementRefCount(formula->left); CtlpFormulaIncrementRefCount(formula->right); break; case Ctlp_AX_c:/* !AX(f1) = EX(!f1)*/ result = FormulaCreateWithType(Ctlp_EX_c); result->left = Ctlp_FormulaConverttoComplement(formula->left); break; case Ctlp_AG_c:/* !AG(f1) = EF(!f1) */ result = FormulaCreateWithType(Ctlp_EF_c); result->left = Ctlp_FormulaConverttoComplement(formula->left); break; case Ctlp_AF_c: /* !AF(f1) = EG(!f1)*/ result = FormulaCreateWithType(Ctlp_EG_c); result->left = Ctlp_FormulaConverttoComplement(formula->left); break; case Ctlp_AU_c: /* !(ApUq) = (E(!q)U(!(p+q)))+(EG!q)*/ result = FormulaCreateWithType(Ctlp_OR_c); result->left = FormulaCreateWithType(Ctlp_EU_c); result->left->left = Ctlp_FormulaConverttoComplement(formula->right); result->left->right = FormulaCreateWithType(Ctlp_NOT_c); result->left->right->left= FormulaCreateWithType(Ctlp_OR_c); result->left->right->left->left = formula->left; result->left->right->left->right = formula->right; result->right = FormulaCreateWithType(Ctlp_EG_c); result->right->left = Ctlp_FormulaConverttoComplement(formula->right); CtlpFormulaIncrementRefCount(formula->left); CtlpFormulaIncrementRefCount(formula->right); break; case Ctlp_TRUE_c:/* !TRUE = FALSE*/ result = FormulaCreateWithType(Ctlp_FALSE_c); break; case Ctlp_FALSE_c:/*!FALSE = TRUE*/ result = FormulaCreateWithType(Ctlp_TRUE_c); break; case Ctlp_Init_c: /* ???*/ case Ctlp_Cmp_c: /* ???*/ /* if (formula->compareValue == 0) tmpString = util_strcat3("[", s1, "] = "); else tmpString = util_strcat3("[", s1, "] != "); result = util_strcat3(tmpString, s2, ""); break;*/ case Ctlp_FwdU_c: /* ???*/ case Ctlp_FwdG_c: /* ??? */ case Ctlp_EY_c: /* ??? */ result = formula; break; default: fail("Unexpected type"); } return result; } /*****************************************************************************/ /**Function******************************************************************** Synopsis [Frees an array of CTL formulas.] Description [Calls CtlpFormulaDecrementRefCount on each formula in formulaArray, and then frees the array itself. It is okay to call this function with an empty array, but it is an error to call it with a NULL array.] SideEffects [] SeeAlso [Ctlp_FormulaFree] ******************************************************************************/ void Ctlp_FormulaArrayFree( array_t * formulaArray /* of Ctlp_Formula_t */) { int i; int numFormulas = array_n(formulaArray); assert(formulaArray != NIL(array_t)); for (i = 0; i < numFormulas; i++) { Ctlp_Formula_t *formula = array_fetch(Ctlp_Formula_t *, formulaArray, i); CtlpFormulaDecrementRefCount(formula); } array_free(formulaArray); } /**Function******************************************************************** Synopsis [Converts a CTL formula to existential form.] Description [Converts a CTL formula to existential form. That is, all universal path quantifiers are replaced with the appropriate combination of existential quantifiers and Boolean negation. Also converts "finally" operators to "until" operators.
Returns a new formula that shares absolutely nothing with the original formula (not even the strings). Also, the new formula does not have any MDDs associated with it. The "originalFormula" field of each new subformula is set to point to the formula passed as an argument. In addition, if (and only if) the original formula is of type AG, AX, AU, AF, or EF, the "converted flag" is set. Returns NULL if called with a NULL formula.
Note: the debugger takes advantage of the exact way that the conversion is done. Hence, you cannot play around much with the syntax of the converted formula.
A list of conversion rules shouls be included here (RB).
The formula is ECTL if every temporal operator appears under an even
number of negations, and it is ACTL if every temporal operator appears under
an odd number of negations. It is quantifier-free if it is both ECTL and
ACTL (i.e., no temporal operators occur), and it is mixed if it is neither
ECTL nor ACTL.]
SideEffects []
SeeAlso []
******************************************************************************/
Ctlp_FormulaClass
Ctlp_CheckClassOfExistentialFormula(
Ctlp_Formula_t *formula)
{
Ctlp_FormulaType formulaType;
Ctlp_Formula_t *rightFormula, *leftFormula;
Ctlp_FormulaClass resultLeft, resultRight, tempResult, currentClass;
assert(formula != NIL(Ctlp_Formula_t));
if(formula == NIL(Ctlp_Formula_t))
return Ctlp_QuantifierFree_c;
formulaType = Ctlp_FormulaReadType(formula);
leftFormula = Ctlp_FormulaReadLeftChild(formula);
rightFormula = Ctlp_FormulaReadRightChild(formula);
/* Depending on the formula type, create result or recur */
switch (formulaType) {
case Ctlp_EX_c:
case Ctlp_EG_c:
case Ctlp_EF_c:
case Ctlp_EU_c:
case Ctlp_FwdU_c:
case Ctlp_FwdG_c:
case Ctlp_EY_c:
case Ctlp_EH_c:
resultLeft = Ctlp_CheckClassOfExistentialFormula(leftFormula);
if (formulaType == Ctlp_EU_c || formulaType == Ctlp_FwdU_c ||
formulaType == Ctlp_FwdG_c )
resultRight = Ctlp_CheckClassOfExistentialFormula(rightFormula);
else
resultRight = Ctlp_QuantifierFree_c;
tempResult = CtlpResolveClass(resultLeft, resultRight);
currentClass = Ctlp_ECTL_c;
return CtlpResolveClass(currentClass, tempResult);
case Ctlp_AX_c:
case Ctlp_AG_c:
case Ctlp_AF_c:
case Ctlp_AU_c:
/* The formula is supposed to be only existential */
fprintf(vis_stdout,
"** Ctlp Error: unexpected (universal) operator type\n");
assert(0);
return Ctlp_Mixed_c;
case Ctlp_OR_c:
case Ctlp_AND_c:
resultLeft = Ctlp_CheckClassOfExistentialFormula(leftFormula);
resultRight = Ctlp_CheckClassOfExistentialFormula(rightFormula);
return CtlpResolveClass(resultLeft, resultRight);
case Ctlp_NOT_c:
tempResult = Ctlp_CheckClassOfExistentialFormula(leftFormula);
return CtlpNegateFormulaClass(tempResult);
case Ctlp_THEN_c:
resultLeft = Ctlp_CheckClassOfExistentialFormula(leftFormula);
resultRight = Ctlp_CheckClassOfExistentialFormula(rightFormula);
tempResult = CtlpNegateFormulaClass(resultLeft);
return CtlpResolveClass(tempResult, resultRight);
case Ctlp_XOR_c:
case Ctlp_EQ_c:
resultLeft = Ctlp_CheckClassOfExistentialFormula(leftFormula);
resultRight = Ctlp_CheckClassOfExistentialFormula(rightFormula);
tempResult = CtlpResolveClass(resultLeft, resultRight);
if( tempResult == Ctlp_QuantifierFree_c)
return Ctlp_QuantifierFree_c;
else
return Ctlp_Mixed_c;
case Ctlp_ID_c:
case Ctlp_TRUE_c:
case Ctlp_FALSE_c:
case Ctlp_Init_c:
return Ctlp_QuantifierFree_c;
case Ctlp_Cmp_c:
return Ctlp_Mixed_c;
default:
fprintf(vis_stderr, "**Ctlp Error: Unexpected operator detected.\n");
assert(0);
return Ctlp_Mixed_c;
}
} /* End of Ctlp_CheckTypeOfExistentialFormula */
/**Function********************************************************************
Synopsis [Tests if an array of simple existential formulae has only
ACTL, only ECTL or mixture of formula.]
Description [Returns Ctlp_ECTL_c if the array contains only
ECTL formulae, Ctlp_ACTL_c if it contains only ACTL formulae,
Ctlp_QuantifierFree_c if there are no quantifiers in any formulae,
and Ctlp_Mixed otherwise.]
SideEffects []
SeeAlso [Ctlp_CheckClassOfExistentialFormula]
******************************************************************************/
Ctlp_FormulaClass
Ctlp_CheckClassOfExistentialFormulaArray(
array_t *formulaArray)
{
Ctlp_FormulaClass result;
Ctlp_Formula_t *formula;
int formulanr;
result = Ctlp_QuantifierFree_c;
arrayForEachItem(Ctlp_Formula_t *, formulaArray, formulanr, formula){
Ctlp_FormulaClass formulaType;
formulaType = Ctlp_CheckClassOfExistentialFormula(formula);
result = CtlpResolveClass(result, formulaType);
if(result == Ctlp_Mixed_c)
return result;
}
return result;
} /* End of Ctlp_CheckTypeOfExistentialFormulaArray */
/**Function********************************************************************
Synopsis [Compare two formulas for equality]
Description [Checks if two formulas are syntactically the same. Equivalent
constructions such as TRUE and TRUE+FALSE are not recognized, but copies are
handled correctly, and strings are compared using strcmp.]
SideEffects []
SeeAlso [FormulaCompare]
******************************************************************************/
boolean
Ctlp_FormulaIdentical(
Ctlp_Formula_t *formula1,
Ctlp_Formula_t *formula2)
{
return(FormulaCompare((char *)formula1, (char *)formula2) == 0);
}
/**Function********************************************************************
Synopsis [Replaces non-monotonic operators in a formula.]
Description [This function takes a parse tree for a CTL formula and
transforms it into another tree that has only monotonic operators.
The non-monotonic operators are
It is important that the original formula be a tree. The idea is that this
function should be called right after reading the formulae from file. Since
the information attached to the parse tree by the model checking procedures
is not preserved, it is also important that no such information exists.
These conditions are checked by an assertion.
This function does not deal with the forward CTL operators. Reduction to
monotonic operators should be performed before conversion to forward CTL.]
SideEffects [The argument is modified. The new formulae will apprear
when they are printed out.]
SeeAlso [Ctlp_FormulaArrayMakeMonotonic]
******************************************************************************/
void
Ctlp_FormulaMakeMonotonic(
Ctlp_Formula_t *formula)
{
Ctlp_Formula_t *left, *right;
Ctlp_FormulaType type;
if (formula == NIL(Ctlp_Formula_t)) {
return;
}
/* Make sure (recursively) that this (sub)-formula is still in its pristine
* state. Specifically, that the parse graph is a tree.
*/
assert(formula->refCount == 1 &&
formula->states == NIL(mdd_t) &&
formula->underapprox == NIL(mdd_t) &&
formula->overapprox == NIL(mdd_t) &&
formula->latest == Ctlp_Incomparable_c &&
formula->dbgInfo.data == NIL(void) &&
formula->dbgInfo.freeFn == (Ctlp_DbgInfoFreeFn) NULL &&
formula->dbgInfo.convertedFlag == FALSE &&
formula->dbgInfo.originalFormula == NIL(Ctlp_Formula_t) &&
formula->top == 0 &&
formula->compareValue == 0
);
type = Ctlp_FormulaReadType(formula);
/* Leaves remain unchanged. */
if (type == Ctlp_ID_c || type == Ctlp_TRUE_c || type == Ctlp_FALSE_c) {
return;
}
/* First recursively fix the children. */
left = Ctlp_FormulaReadLeftChild(formula);
Ctlp_FormulaMakeMonotonic(left);
right = Ctlp_FormulaReadRightChild(formula);
Ctlp_FormulaMakeMonotonic(right);
/* Fix this node if it is not monotonic. */
switch (type) {
case Ctlp_EX_c:
case Ctlp_EG_c:
case Ctlp_EF_c:
case Ctlp_EU_c:
case Ctlp_AX_c:
case Ctlp_AG_c:
case Ctlp_AF_c:
case Ctlp_AU_c:
case Ctlp_OR_c:
case Ctlp_AND_c:
case Ctlp_NOT_c:
case Ctlp_THEN_c:
case Ctlp_EY_c:
case Ctlp_EH_c:
/* Nothing to be done */
break;
case Ctlp_EQ_c: {
Ctlp_Formula_t *dupLeft, *dupRight;
Ctlp_Formula_t *thenLeft, *thenRight;
dupLeft = Ctlp_FormulaDup(left);
dupRight = Ctlp_FormulaDup(right);
thenLeft = Ctlp_FormulaCreate(Ctlp_THEN_c, left, right);
thenRight = Ctlp_FormulaCreate(Ctlp_THEN_c, dupRight, dupLeft);
/* Fix the node in place. */
formula->type = Ctlp_AND_c;
formula->left = thenLeft;
formula->right = thenRight;
break;
}
case Ctlp_XOR_c: {
Ctlp_Formula_t *dupLeft, *dupRight;
Ctlp_Formula_t *negLeft, *negRight;
Ctlp_Formula_t *andLeft, *andRight;
dupLeft = Ctlp_FormulaDup(left);
dupRight = Ctlp_FormulaDup(right);
negLeft = Ctlp_FormulaCreate(Ctlp_NOT_c, dupLeft, NIL(Ctlp_Formula_t));
negRight = Ctlp_FormulaCreate(Ctlp_NOT_c, dupRight, NIL(Ctlp_Formula_t));
andLeft = Ctlp_FormulaCreate(Ctlp_AND_c, left, negRight);
andRight = Ctlp_FormulaCreate(Ctlp_AND_c, negLeft, right);
/* Fix the node in place. */
formula->type = Ctlp_OR_c;
formula->left = andLeft;
formula->right = andRight;
break;
}
default:
/* Forward CTL operators (that are not supported) and leaves (that are
* dealt with above) would fall here.
*/
fail("unexpected CTL formula type\n");
}
return;
} /* Ctlp_FormulaMakeMonotonic */
/**Function********************************************************************
Synopsis [Replaces non-monotonic operators in an array of formulae.]
Description [Apply Ctlp_FormulaMakeMonotonic to each formula in the array.]
SideEffects [The formulae in the array are modified.]
SeeAlso [Ctlp_FormulaMakeMonotonic]
******************************************************************************/
void
Ctlp_FormulaArrayMakeMonotonic(
array_t *formulaArray /* of Ctlp_Formula_t */)
{
int i;
Ctlp_Formula_t *formula;
if (formulaArray == NIL(array_t)) return;
arrayForEachItem(Ctlp_Formula_t *, formulaArray, i, formula) {
Ctlp_FormulaMakeMonotonic(formula);
}
} /* Ctlp_FormulaArrayMakeMonotonic */
/*---------------------------------------------------------------------------*/
/* Definition of internal functions */
/*---------------------------------------------------------------------------*/
/**Function********************************************************************
Synopsis [Increments the reference count of a formula.]
Description [The function increments the reference count of a formula. If
the formula is NULL, the function does nothing.]
SideEffects []
SeeAlso []
******************************************************************************/
void
CtlpFormulaIncrementRefCount(
Ctlp_Formula_t *formula)
{
if(formula!=NIL(Ctlp_Formula_t)) {
++(formula->refCount);
}
}
/**Function********************************************************************
Synopsis [Decrements the reference count of a formula.]
Description [The function decrements the reference count of formula and if
the reference count reaches 0, the formula is freed. If the formula is NULL,
the function does nothing. It is an error to decrement the reference count
below 0.]
SideEffects []
SeeAlso []
******************************************************************************/
void
CtlpFormulaDecrementRefCount(
Ctlp_Formula_t *formula)
{
if(formula!=NIL(Ctlp_Formula_t)) {
assert(formula->refCount>0);
if(--(formula->refCount) == 0)
CtlpFormulaFree(formula);
}
}
/**Function********************************************************************
Synopsis [Adds formula to the end of globalFormulaArray.]
SideEffects [Manipulates the global variable globalFormulaArray.]
SeeAlso [CtlpYyparse]
******************************************************************************/
void
CtlpFormulaAddToGlobalArray(
Ctlp_Formula_t * formula)
{
array_insert_last(Ctlp_Formula_t *, globalFormulaArray, formula);
}
/**Function********************************************************************
Synopsis [Frees a CTL formula.]
Description [The function frees all memory associated with the formula,
including all MDDs and all character strings (however, does not free
dbgInfo.originalFormula). It also decrements the reference counts of its two
chidren. The function does nothing if formula is NULL.]
SideEffects []
SeeAlso [Ctlp_FormulaArrayFree]
******************************************************************************/
void
CtlpFormulaFree(
Ctlp_Formula_t * formula)
{
if (formula != NIL(Ctlp_Formula_t)) {
/*
* Free any fields that are not NULL.
*/
if (formula->type == Ctlp_ID_c) {
FREE(formula->left);
FREE(formula->right);
}
else {
if (formula->left != NIL(Ctlp_Formula_t)) {
CtlpFormulaDecrementRefCount(formula->left);
}
if (formula->right != NIL(Ctlp_Formula_t)) {
CtlpFormulaDecrementRefCount(formula->right);
}
}
if (formula->states != NIL(mdd_t))
mdd_free(formula->states);
if (formula->underapprox != NIL(mdd_t))
mdd_free(formula->underapprox);
if (formula->overapprox != NIL(mdd_t))
mdd_free(formula->overapprox);
if (formula->Bottomstates != NIL(array_t))
mdd_array_free(formula->Bottomstates);
if (formula->Topstates != NIL(array_t))
mdd_array_free(formula->Topstates);
if (formula->matchfound_top != NIL(array_t))
array_free(formula->matchfound_top);
if (formula->matchelement_top != NIL(array_t))
array_free(formula->matchelement_top);
if (formula->matchfound_bot != NIL(array_t))
array_free(formula->matchfound_bot);
if (formula->matchelement_bot != NIL(array_t))
array_free(formula->matchelement_bot);
if (formula->leaves != NIL(array_t))
array_free(formula->leaves);
if (formula->dbgInfo.data != NIL(void)) {
(*formula->dbgInfo.freeFn)(formula);
}
FREE(formula);
}
}
/**Function********************************************************************
Synopsis [Create a binary string of given value with size of interval ]
Description [The value is a binary string starting with 'b',
a hexadecimal string starting with 'x', or an
integer string. If Value is not fitted in the interval, 0 is return.
Otherwise 1 is returned. Result string is saved at given pointer.]
SideEffects []
SeeAlso []
******************************************************************************/
int
CtlpStringChangeValueStrToBinString(
char *value,
char *binValueStr,
int interval)
{
int i;
long int num, mask;
double maxNum;
char *ptr;
mask = 1;
maxNum = pow(2.0,(double)interval);
errno = 0;
if(value[0] == 'b'){
if ((int)strlen(value)-1 == interval){
for(i=1;i<=interval;i++){
if (value[i] == '0' || value[i] == '1'){
binValueStr[i-1] = value[i];
}else{
return 0;
}
}
binValueStr[interval] = '\0';
}else{
return 0;
}
}else if (value[0] == 'x'){
for(i=1; i < (int)strlen(value); i++){
if (!isxdigit((int)value[i])){
return 0;
}
}
num = strtol(++value,&ptr,16);
if (errno) return 0;
if ( num >= maxNum) return 0;
for(i=0;i
AG phi turns into !EU(true,! phi'), where the top ! has converted set
and points to the AG, and phi' points to phi.
AU?
AX?
Any others?
]
SideEffects []
SeeAlso [Ctlp_FormulaArrayConvertToExistentialForm,
Ctlp_ConvertToSimpleExistentialForm]
******************************************************************************/
Ctlp_Formula_t *
Ctlp_FormulaConvertToExistentialForm(
Ctlp_Formula_t * formula)
{
Ctlp_Formula_t *new_;
char *variableNameCopy, *valueNameCopy;
if (formula == NIL(Ctlp_Formula_t)) {
return NIL(Ctlp_Formula_t);
}
/*
* Recursively convert each subformula.
*/
switch(formula->type) {
case Ctlp_EF_c:
/* EFf --> (E true U f) */
new_ = FormulaCreateWithType(Ctlp_EU_c);
new_->left = FormulaCreateWithType(Ctlp_TRUE_c);
new_->right = Ctlp_FormulaConvertToExistentialForm(formula->left);
new_->dbgInfo.convertedFlag = TRUE;
break;
case Ctlp_AX_c:
/* AXf --> !(EX(!f)) */
new_ = FormulaCreateWithType(Ctlp_NOT_c);
new_->left = FormulaCreateWithType(Ctlp_EX_c);
new_->left->left = FormulaCreateWithType(Ctlp_NOT_c);
new_->left->left->left = Ctlp_FormulaConvertToExistentialForm(formula->left);
new_->dbgInfo.convertedFlag = TRUE;
break;
case Ctlp_AG_c:
/* AGf --> ![(E true U !f)] */
new_ = FormulaCreateWithType(Ctlp_NOT_c);
new_->left = FormulaCreateWithType(Ctlp_EU_c);
new_->left->left = FormulaCreateWithType(Ctlp_TRUE_c);
new_->left->right = FormulaCreateWithType(Ctlp_NOT_c);
new_->left->right->left = Ctlp_FormulaConvertToExistentialForm(formula->left);
new_->dbgInfo.convertedFlag = TRUE;
break;
case Ctlp_AF_c:
/* AFf --> ![EG(!f)] */
new_ = FormulaCreateWithType(Ctlp_NOT_c);
new_->left = FormulaCreateWithType(Ctlp_EG_c);
new_->left->left = FormulaCreateWithType(Ctlp_NOT_c);
new_->left->left->left = Ctlp_FormulaConvertToExistentialForm(formula->left);
new_->dbgInfo.convertedFlag = TRUE;
break;
case Ctlp_AU_c:
/* A[fUg] --> !((E[!g U (!f*!g)]) + (EG!g)) */
new_ = FormulaCreateWithType(Ctlp_NOT_c); /* top */
new_->left = FormulaCreateWithType(Ctlp_OR_c); /* ((E[!g U (!f*!g)]) + (EG!g)) */
new_->left->right = FormulaCreateWithType(Ctlp_EG_c); /* EG !g */
new_->left->right->left = FormulaCreateWithType(Ctlp_NOT_c); /* !g */
new_->left->right->left->left = Ctlp_FormulaConvertToExistentialForm(formula->right); /* g */
new_->left->left = FormulaCreateWithType(Ctlp_EU_c); /* E[!g U (!f*!g)] */
new_->left->left->left = FormulaCreateWithType(Ctlp_NOT_c); /* !g */
new_->left->left->left->left = Ctlp_FormulaConvertToExistentialForm(formula->right); /* g */
new_->left->left->right = FormulaCreateWithType(Ctlp_AND_c); /* !f*!g */
new_->left->left->right->left = FormulaCreateWithType(Ctlp_NOT_c); /* !f */
new_->left->left->right->left->left = Ctlp_FormulaConvertToExistentialForm(formula->left); /* f */
new_->left->left->right->right = FormulaCreateWithType(Ctlp_NOT_c); /* !g */
new_->left->left->right->right->left = Ctlp_FormulaConvertToExistentialForm(formula->right); /* g */
new_->dbgInfo.convertedFlag = TRUE;
break;
case Ctlp_ID_c:
/* Make a copy of the name, and create a new formula. */
variableNameCopy = util_strsav((char *)(formula->left));
valueNameCopy = util_strsav((char *)(formula->right));
new_ = Ctlp_FormulaCreate(Ctlp_ID_c, variableNameCopy, valueNameCopy);
break;
case Ctlp_THEN_c:
case Ctlp_EX_c:
case Ctlp_EG_c:
case Ctlp_EU_c:
case Ctlp_OR_c:
case Ctlp_AND_c:
case Ctlp_NOT_c:
case Ctlp_XOR_c:
case Ctlp_EQ_c:
case Ctlp_TRUE_c:
case Ctlp_FALSE_c:
/* These are already in the correct form. Just convert subformulas. */
new_ = FormulaCreateWithType(formula->type);
new_->left = Ctlp_FormulaConvertToExistentialForm(formula->left);
new_->right = Ctlp_FormulaConvertToExistentialForm(formula->right);
break;
default:
fail("Unexpected type");
}
new_->dbgInfo.originalFormula = formula;
return new_;
}
/**Function********************************************************************
Synopsis [Converts a CTL formula to simple existential form.]
Description [Converts a CTL formula to simple existential form.
That is, all universal path quantifiers are replaced with the
appropriate combination of existential quantifiers and Boolean
negation. Only `NOT' and `AND' Boolean operators are allowed. Also
converts "finally" operators to "until" operators.
The converted bit is set in the converted formula only when temporal
operators are converted, not when boolean operators are converted.
A new formula is created that needs to be freed seperately.]
SideEffects []
Remarks [Ctl formulas in simple existential form are incompatible
with the mc debug routines. The reason is that the debug routines
count on a very specific form of the converted formula to conclude
what the original formula was.]
SeeAlso [Ctlp_FormulaArrayConvertToExistentialForm]
******************************************************************************/
Ctlp_Formula_t *
Ctlp_FormulaConvertToSimpleExistentialForm(
Ctlp_Formula_t * formula)
{
Ctlp_Formula_t *new_;
char *variableNameCopy, *valueNameCopy;
if (formula == NIL(Ctlp_Formula_t)) {
return NIL(Ctlp_Formula_t);
}
/*
* Recursively convert each subformula.
*/
switch(formula->type) {
case Ctlp_EF_c:
/* EFf --> (E true U f) */
new_ = FormulaCreateWithType(Ctlp_EU_c);
new_->left = FormulaCreateWithType(Ctlp_TRUE_c);
new_->right = Ctlp_FormulaConvertToSimpleExistentialForm(formula->left);
new_->dbgInfo.convertedFlag = TRUE;
break;
case Ctlp_AX_c:
/* AXf --> !(EX(!f)) */
new_ = FormulaCreateWithType(Ctlp_NOT_c);
new_->left = FormulaCreateWithType(Ctlp_EX_c);
new_->left->left = FormulaCreateWithType(Ctlp_NOT_c);
new_->left->left->left =
Ctlp_FormulaConvertToSimpleExistentialForm(formula->left);
new_->dbgInfo.convertedFlag = TRUE;
break;
case Ctlp_AG_c:
/* AGf --> ![(E true U !f)] */
new_ = FormulaCreateWithType(Ctlp_NOT_c);
new_->left = FormulaCreateWithType(Ctlp_EU_c);
new_->left->left = FormulaCreateWithType(Ctlp_TRUE_c);
new_->left->right = FormulaCreateWithType(Ctlp_NOT_c);
new_->left->right->left =
Ctlp_FormulaConvertToSimpleExistentialForm(formula->left);
new_->dbgInfo.convertedFlag = TRUE;
break;
case Ctlp_AF_c:
/* AFf --> ![EG(!f)] */
new_ = FormulaCreateWithType(Ctlp_NOT_c);
new_->left = FormulaCreateWithType(Ctlp_EG_c);
new_->left->left = FormulaCreateWithType(Ctlp_NOT_c);
new_->left->left->left = Ctlp_FormulaConvertToSimpleExistentialForm(formula->left);
new_->dbgInfo.convertedFlag = TRUE;
break;
case Ctlp_AU_c:
/* A[fUg] --> !(E[!g U (!f*!g)]) * !(EG!g)) */
new_ = FormulaCreateWithType(Ctlp_AND_c); /* top */
new_->left = FormulaCreateWithType(Ctlp_NOT_c);
new_->right = FormulaCreateWithType(Ctlp_NOT_c);
new_->left->left = FormulaCreateWithType(Ctlp_EG_c); /* EG !g */
new_->left->left->left = FormulaCreateWithType(Ctlp_NOT_c); /* !g */
new_->left->left->left->left =
Ctlp_FormulaConvertToSimpleExistentialForm(formula->right); /* g */
new_->right->left = FormulaCreateWithType(Ctlp_EU_c); /* E[!g U (!f*!g)] */
new_->right->left->left = FormulaCreateWithType(Ctlp_NOT_c); /* !g */
new_->right->left->left->left =
Ctlp_FormulaConvertToSimpleExistentialForm(formula->right); /* g */
new_->right->left->right = FormulaCreateWithType(Ctlp_AND_c); /* !f*!g */
new_->right->left->right->left = FormulaCreateWithType(Ctlp_NOT_c); /* !f */
new_->right->left->right->left->left =
Ctlp_FormulaConvertToSimpleExistentialForm(formula->left); /* f */
new_->right->left->right->right = FormulaCreateWithType(Ctlp_NOT_c); /* !g */
new_->right->left->right->right->left =
Ctlp_FormulaConvertToSimpleExistentialForm(formula->right); /* g */
new_->dbgInfo.convertedFlag = TRUE;
break;
case Ctlp_ID_c:
/* Make a copy of the name, and create a new formula. */
variableNameCopy = util_strsav((char *)(formula->left));
valueNameCopy = util_strsav((char *)(formula->right));
new_ = Ctlp_FormulaCreate(Ctlp_ID_c, variableNameCopy, valueNameCopy);
break;
/* RB: I think THEN (and also OR, and maybe some others) should also have converted set. */
case Ctlp_THEN_c:
/* p->q --> !(p * !q) */
new_ = FormulaCreateWithType(Ctlp_NOT_c);
new_->left = FormulaCreateWithType(Ctlp_AND_c);
new_->left->left =
Ctlp_FormulaConvertToSimpleExistentialForm(formula->left);
new_->left->right = FormulaCreateWithType(Ctlp_NOT_c);
new_->left->right->left =
Ctlp_FormulaConvertToSimpleExistentialForm(formula->right);
break;
case Ctlp_EX_c:
case Ctlp_EG_c:
case Ctlp_EU_c:
case Ctlp_AND_c:
case Ctlp_NOT_c:
case Ctlp_TRUE_c:
case Ctlp_FALSE_c:
/* These are already in the correct form. Just convert subformulas. */
new_ = FormulaCreateWithType(formula->type);
new_->left = Ctlp_FormulaConvertToSimpleExistentialForm(formula->left);
new_->right = Ctlp_FormulaConvertToSimpleExistentialForm(formula->right);
break;
case Ctlp_OR_c:
/* p + q --> !(!p * !q) */
new_ = FormulaCreateWithType(Ctlp_NOT_c);
new_->left = FormulaCreateWithType(Ctlp_AND_c);
new_->left->left = FormulaCreateWithType(Ctlp_NOT_c);
new_->left->right = FormulaCreateWithType(Ctlp_NOT_c);
new_->left->left->left =
Ctlp_FormulaConvertToSimpleExistentialForm(formula->left);
new_->left->right->left =
Ctlp_FormulaConvertToSimpleExistentialForm(formula->right);
break;
case Ctlp_XOR_c:
/* p ^ q --> !(p * q) * !(!p * !q) */
new_ = FormulaCreateWithType(Ctlp_AND_c);
new_->left = FormulaCreateWithType(Ctlp_NOT_c);
new_->left->left = FormulaCreateWithType(Ctlp_AND_c);
new_->left->left->left =
Ctlp_FormulaConvertToSimpleExistentialForm(formula->left);
new_->left->left->right =
Ctlp_FormulaConvertToSimpleExistentialForm(formula->right);
new_->right = FormulaCreateWithType(Ctlp_NOT_c);
new_->right->left = FormulaCreateWithType(Ctlp_AND_c);
new_->right->left->left = FormulaCreateWithType(Ctlp_NOT_c);
new_->right->left->left->left =
Ctlp_FormulaConvertToSimpleExistentialForm(formula->left);
new_->right->left->right = FormulaCreateWithType(Ctlp_NOT_c);
new_->right->left->right->left =
Ctlp_FormulaConvertToSimpleExistentialForm(formula->right);
break;
case Ctlp_EQ_c:
/* p <-> q --> !(p * !q) * !(!p * q) */
new_ = FormulaCreateWithType(Ctlp_AND_c);
new_->left = FormulaCreateWithType(Ctlp_NOT_c);
new_->left->left = FormulaCreateWithType(Ctlp_AND_c);
new_->left->left->left =
Ctlp_FormulaConvertToSimpleExistentialForm(formula->left);
new_->left->left->right = FormulaCreateWithType(Ctlp_NOT_c);
new_->left->left->right->left =
Ctlp_FormulaConvertToSimpleExistentialForm(formula->right);
new_->right = FormulaCreateWithType(Ctlp_NOT_c);
new_->right->left = FormulaCreateWithType(Ctlp_AND_c);
new_->right->left->left = FormulaCreateWithType(Ctlp_NOT_c);
new_->right->left->left->left =
Ctlp_FormulaConvertToSimpleExistentialForm(formula->left);
new_->right->left->right =
Ctlp_FormulaConvertToSimpleExistentialForm(formula->right);
break;
default:
fail("Unexpected type");
}
new_->dbgInfo.originalFormula = formula;
return new_;
}
/**Function********************************************************************
Synopsis [Converts an array of CTL formulas to existential form.]
Description [Calls Ctlp_FormulaConvertToExistentialForm on each formula. It
is okay to call this function with an empty array (in which case an empty
array is returned), but it is an error to call it with a NULL array.
All formulas in the array are copied, and hence Ctlp_FormulaArrayFree() needs
to be called on the result at the end.]
SideEffects []
SeeAlso [Ctlp_FormulaConvertToExistentialForm]
******************************************************************************/
array_t *
Ctlp_FormulaArrayConvertToExistentialFormTree(
array_t * formulaArray /* of Ctlp_Formula_t */)
{
int i;
int numFormulas = array_n(formulaArray);
array_t *convertedArray = array_alloc(Ctlp_Formula_t *, numFormulas);
assert(formulaArray != NIL(array_t));
for (i = 0; i < numFormulas; i++) {
Ctlp_Formula_t *formula = array_fetch(Ctlp_Formula_t *, formulaArray, i);
Ctlp_Formula_t *convertedFormula = Ctlp_FormulaConvertToExistentialForm(formula);
array_insert(Ctlp_Formula_t *, convertedArray, i, convertedFormula);
}
return convertedArray;
}
/**Function********************************************************************
Synopsis [Converts an array of CTL formulas to simple existential form.]
Description [Calls Ctlp_FormulaConvertToSimpleExistentialForm on
each formula. It is okay to call this function with an empty array
(in which case an empty array is returned), but it is an error to
call it with a NULL array.]
SideEffects []
SeeAlso [Ctlp_FormulaConvertToExistentialForm]
******************************************************************************/
array_t *
Ctlp_FormulaArrayConvertToSimpleExistentialFormTree(
array_t * formulaArray /* of Ctlp_Formula_t */)
{
int i;
int numFormulas;
array_t *convertedArray;
assert( formulaArray != NIL(array_t));
numFormulas = array_n(formulaArray);
convertedArray = array_alloc(Ctlp_Formula_t *, numFormulas);
for (i = 0; i < numFormulas; i++) {
Ctlp_Formula_t *formula;
Ctlp_Formula_t *convertedFormula;
formula = array_fetch(Ctlp_Formula_t *, formulaArray, i);
convertedFormula = Ctlp_FormulaConvertToSimpleExistentialForm(formula);
array_insert(Ctlp_Formula_t *, convertedArray, i, convertedFormula);
}
return convertedArray;
}
/**Function********************************************************************
Synopsis [Converts an array of CTL formulae to a multi-rooted DAG.]
Description [The function hashes each subformula of a formula
(including the formula itself) into a uniqueTable. It returns an
array containing the roots of the multi-rooted DAG thus created by
the sharing of the subformulae. It is okay to call this function
with an empty array (in which case an empty array is returned), but
it is an error to call it with a NULL array.]
SideEffects [A formula in formulaArray might be freed if it had been
encountered as a subformula of some other formula. Other formulae in
formulaArray might be present in the returned array. Therefore, the
formulae in formulaArray should not be freed. Only formulaArray
itself should be freed.
RB: What does that mean?
I understand this as follows. Copies of the formulae are not made,
but rather pointers to the argument subformulae are kept. Hence, not only
should the formulae in the result not be freed, but also you cannot free the
argument before you are done with the result. Furthermore, by invocation of
this function, the argument gets altered. It is still valid, but pointers
may have changed. Is this correct?
RB rewrite: A formula in formulaArray is freed if it is encountered as a
subformula of some other formula. Other formulae in formulaArray might be
present in the returned array. Therefore, the formulae in formulaArray should
not be freed. Only formulaArray itself should be freed.]
SeeAlso []
******************************************************************************/
array_t *
Ctlp_FormulaArrayConvertToDAG(
array_t *formulaArray)
{
int i;
Ctlp_Formula_t *formula, *uniqueFormula;
st_table *uniqueTable = st_init_table(FormulaCompare, FormulaHash);
int numFormulae = array_n(formulaArray);
array_t *rootsOfFormulaDAG = array_alloc(Ctlp_Formula_t *, numFormulae);
assert(formulaArray != NIL(array_t));
for(i=0; i < numFormulae; i++) {
formula = array_fetch(Ctlp_Formula_t *, formulaArray, i);
uniqueFormula = FormulaHashIntoUniqueTable(formula, uniqueTable);
if(uniqueFormula != formula) {
CtlpFormulaDecrementRefCount(formula);
CtlpFormulaIncrementRefCount(uniqueFormula);
array_insert(Ctlp_Formula_t *, rootsOfFormulaDAG, i, uniqueFormula);
}
else
array_insert(Ctlp_Formula_t *, rootsOfFormulaDAG, i, formula);
}
st_free_table(uniqueTable);
return rootsOfFormulaDAG;
}
/**Function********************************************************************
Synopsis [Converts a DAG of CTL formulae to a DAG of existential CTL
formulae.]
Description [The function converts a DAG of CTL formulae to a DAG of
existential CTL formulae. The function recursively converts each
subformula of each of the formulae in the DAG and remembers the
converted formula in the field states. It is okay to call this
function with an empty array (in which case an empty array is
returned), but it is an error to call it with a NULL array.
The states fileds in the formula need to be NULL.]
SideEffects []
SeeAlso [FormulaConvertToExistentialDAG]
******************************************************************************/
array_t *
Ctlp_FormulaDAGConvertToExistentialFormDAG(
array_t *formulaDAG)
{
int i;
Ctlp_Formula_t *formula;
int numFormulae = array_n(formulaDAG);
array_t *existentialFormulaDAG = array_alloc(Ctlp_Formula_t *, numFormulae);
assert( formulaDAG != NIL(array_t));
for(i=0; iXOR
and EQ
.
They are replaced by eqivalent trees. Specificallt, XOR(a,b)
is replaced by OR(AND(a,NOT(b)),AND(NOT(a),b))
and
f <-> g
is replaced by AND(f->g,g->f)
.