blob: 4f5605542084bf9505e4e47d003d1af3956363a8 [file] [log] [blame]
/**************************************************************/
/* ********************************************************** */
/* * * */
/* * ANALYSIS OF CLAUSE SETS * */
/* * * */
/* * $Module: ANALYZE * */
/* * * */
/* * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 * */
/* * MPI fuer Informatik * */
/* * * */
/* * This program is free software; you can redistribute * */
/* * it and/or modify it under the terms of the GNU * */
/* * General Public License as published by the Free * */
/* * Software Foundation; either version 2 of the License, * */
/* * or (at your option) any later version. * */
/* * * */
/* * This program is distributed in the hope that it will * */
/* * be useful, but WITHOUT ANY WARRANTY; without even * */
/* * the implied warranty of MERCHANTABILITY or FITNESS * */
/* * FOR A PARTICULAR PURPOSE. See the GNU General Public * */
/* * License for more details. * */
/* * * */
/* * You should have received a copy of the GNU General * */
/* * Public License along with this program; if not, write * */
/* * to the Free Software Foundation, Inc., 59 Temple * */
/* * Place, Suite 330, Boston, MA 02111-1307 USA * */
/* * * */
/* $Revision$ * */
/* $State$ * */
/* $Date$ * */
/* $Author$ * */
/* * * */
/* * Contact: * */
/* * Christoph Weidenbach * */
/* * MPI fuer Informatik * */
/* * Stuhlsatzenhausweg 85 * */
/* * 66123 Saarbruecken * */
/* * Email: weidenb@mpi-sb.mpg.de * */
/* * Germany * */
/* * * */
/* ********************************************************** */
/**************************************************************/
/* $RCSfile$ */
#include <stdio.h>
#include "analyze.h"
static LIST ana_CalculatePredicatePrecedence(LIST, LIST);
static LIST ana_CalculateFunctionPrecedence(LIST, LIST, FLAGSTORE);
/**************************************************************/
/* Global Variables */
/**************************************************************/
LIST ana_FINITEMONADICPREDICATES; /* List of monadic predicates with finite extension */
BOOL ana_EQUATIONS; /* Problem contains any equations at all */
static BOOL ana_PEQUATIONS; /* Problem contains positive equations */
static BOOL ana_NEQUATIONS; /* Problem contains negative equations */
static BOOL ana_FUNCTIONS; /* Problem contains non-constant function symbols */
static BOOL ana_PROP; /* Problem contains propositional variables */
static BOOL ana_GROUND; /* Problem contains non-propositional, non-equational ground atoms */
static BOOL ana_NONUNIT; /* Problem contains non-unit clauses */
static BOOL ana_MONADIC; /* Problem contains non-ground monadic predicates */
static BOOL ana_NONMONADIC; /* Problem contains non-ground n-place predicates, n>1, not equality */
BOOL ana_SORTRES; /* Problem contains literal not(S(x)) for some S */
BOOL ana_USORTRES; /* Problem contains literal not(S(t)) for some S */
static BOOL ana_FINDOMAIN; /* Problem contains clause implying a finite domain */
static BOOL ana_NONTRIVDOMAIN; /* Problem contains clause implying a domain of size greater one */
static BOOL ana_CONGROUND; /* Conjecture is ground */
static BOOL ana_PUREEQUATIONAL; /* Problem is purely equational */
static BOOL ana_PUREPROPOSITIONAL; /* Problem is purely propositional */
BOOL ana_SORTDECEQUATIONS; /* True if all positive equations are sort decreasing with respect to
the static sort theory contained in the problem */
static BOOL ana_SORTMANYEQUATIONS; /* True if all positive equations have the
same sort on left and right hand side with
respect to the static sort theory
contained in the problem */
static NAT ana_AXIOMCLAUSES; /* Number of axiom clauses */
static NAT ana_CONCLAUSES; /* Number of conjecture clauses */
static NAT ana_NONHORNCLAUSES; /* Number of Non-Horn clauses */
/**************************************************************/
/* Functions */
/**************************************************************/
void ana_AnalyzeProblem(PROOFSEARCH Search, LIST Clauses)
/**************************************************************
INPUT: A proofsearch object and a list of clauses.
RETURNS: Void.
EFFECT: Analyzes the clauses and sets the analyze variables.
Recomputes the weight for the clauses.
<Search> is modified according to clauses: non trivial domain number
is set
***************************************************************/
{
CLAUSE Clause;
ana_EQUATIONS = FALSE;
ana_PEQUATIONS = FALSE; /* Defaults for properties */
ana_NEQUATIONS = FALSE;
ana_FUNCTIONS = FALSE;
ana_FINDOMAIN = FALSE;
ana_NONTRIVDOMAIN = FALSE;
ana_MONADIC = FALSE;
ana_NONMONADIC = FALSE;
ana_PROP = FALSE;
ana_GROUND = FALSE;
ana_SORTRES = FALSE;
ana_USORTRES = FALSE;
ana_NONUNIT = FALSE;
ana_CONGROUND = TRUE;
ana_AXIOMCLAUSES = 0;
ana_CONCLAUSES = 0;
ana_NONHORNCLAUSES = 0;
list_Delete(ana_FINITEMONADICPREDICATES);
ana_FINITEMONADICPREDICATES = list_Nil();
if (list_Empty(Clauses))
return;
ana_FINITEMONADICPREDICATES = clause_FiniteMonadicPredicates(Clauses);
while (!list_Empty(Clauses)) {
Clause = (CLAUSE)list_Car(Clauses);
clause_UpdateWeight(Clause, prfs_Store(Search));
if (clause_GetFlag(Clause,CONCLAUSE))
ana_CONCLAUSES++;
else
ana_AXIOMCLAUSES++;
if (clause_NumOfSuccLits(Clause) > 1)
ana_NONHORNCLAUSES++;
if (ana_CONGROUND && clause_GetFlag(Clause,CONCLAUSE) &&
clause_MaxVar(Clause) != symbol_GetInitialStandardVarCounter())
ana_CONGROUND = FALSE;
if (!ana_PEQUATIONS && clause_ContainsPositiveEquations(Clause)) {
ana_PEQUATIONS = TRUE;
}
if (!ana_NEQUATIONS && clause_ContainsNegativeEquations(Clause)) {
ana_NEQUATIONS = TRUE;
}
if (!ana_MONADIC || !ana_NONMONADIC || !ana_PROP || !ana_GROUND)
clause_ContainsFolAtom(Clause,&ana_PROP,&ana_GROUND,&ana_MONADIC,&ana_NONMONADIC);
if (!ana_FUNCTIONS && clause_ContainsFunctions(Clause)) {
ana_FUNCTIONS = TRUE;
}
if (!ana_FINDOMAIN && clause_ImpliesFiniteDomain(Clause)) {
ana_FINDOMAIN = TRUE;
}
if (!ana_NONTRIVDOMAIN && clause_ImpliesNonTrivialDomain(Clause)) {
prfs_SetNonTrivClauseNumber(Search, clause_Number(Clause));
ana_NONTRIVDOMAIN = TRUE;
}
if (!ana_NONUNIT && clause_Length(Clause) > 1) {
ana_NONUNIT = TRUE;
}
if (!ana_SORTRES || !ana_USORTRES)
clause_ContainsSortRestriction(Clause,&ana_SORTRES,&ana_USORTRES);
Clauses = list_Cdr(Clauses);
}
ana_PUREEQUATIONAL = ((ana_PEQUATIONS || ana_NEQUATIONS) && !ana_MONADIC &&
!ana_NONMONADIC && !ana_PROP && !ana_GROUND);
ana_EQUATIONS = (ana_PEQUATIONS || ana_NEQUATIONS);
ana_PUREPROPOSITIONAL = (!ana_PEQUATIONS && !ana_NEQUATIONS &&!ana_MONADIC &&
!ana_NONMONADIC && ana_PROP);
}
void ana_AnalyzeSortStructure(LIST Clauses, FLAGSTORE Flags,
PRECEDENCE Precedence)
/**************************************************************
INPUT: A list of clauses, a flag store and a precedence.
RETURNS: Nothing.
EFFECT: The sort structure with respect to equations is analyzed.
It is detected whether all equations are many sorted or
sort decreasing.
***************************************************************/
{
if (ana_PEQUATIONS && ana_SORTRES) {
STR Result;
Result = sort_AnalyzeSortStructure(Clauses,Flags,Precedence);
ana_SORTMANYEQUATIONS = (Result == SORTEQMANY);
ana_SORTDECEQUATIONS = (Result == SORTEQMANY || Result == SORTEQDECR);
}
}
void ana_Print(FLAGSTORE Flags, PRECEDENCE Precedence)
/**************************************************************
INPUT: A flag store and a precedence.
RETURNS: Nothing.
EFFECT: The results of an analysis stored in the module variables
is printed to stdout.
***************************************************************/
{
const char* Horn;
if (ana_NONHORNCLAUSES == 0)
Horn = "Horn";
else
Horn = "Non-Horn";
if (ana_MONADIC && !ana_NONMONADIC) {
printf("\n This is a monadic %s problem",Horn);
if (ana_PEQUATIONS || ana_NEQUATIONS)
fputs(" with equality.", stdout);
else
fputs(" without equality.", stdout);
}
else
if (ana_PEQUATIONS || ana_NEQUATIONS) {
if (ana_NONMONADIC || ana_MONADIC || ana_PROP)
printf("\n This is a first-order %s problem containing equality.",Horn);
else
if (ana_NONUNIT)
printf("\n This is a pure equality %s problem.",Horn);
else
fputs("\n This is a unit equality problem.", stdout);
}
else
if (ana_NONMONADIC || ana_MONADIC)
printf("\n This is a first-order %s problem without equality.",Horn);
if (ana_PUREPROPOSITIONAL)
printf("\n This is a propositional %s problem.",Horn);
else
if (ana_FINDOMAIN || !ana_FUNCTIONS) {
fputs("\n This is a problem that has, if any, a finite domain model.",
stdout);
if (ana_FINDOMAIN)
fputs("\n There is a finite domain clause.", stdout);
if (!ana_FUNCTIONS)
fputs("\n There are no function symbols.", stdout);
}
if (ana_NONTRIVDOMAIN)
fputs("\n This is a problem that has, if any, a non-trivial domain model.",
stdout);
if (ana_SORTRES) {
fputs("\n This is a problem that contains sort information.", stdout);
if (ana_PEQUATIONS) {
if (ana_SORTMANYEQUATIONS)
fputs("\n All equations are many sorted.", stdout);
else {
if (ana_SORTDECEQUATIONS)
fputs("\n All equations are sort-decreasing.", stdout);
}
}
}
if (ana_CONCLAUSES > 0 && ana_CONGROUND && !ana_PUREPROPOSITIONAL)
fputs("\n The conjecture is ground.", stdout);
if (!list_Empty(ana_FINITEMONADICPREDICATES)) {
LIST Scan;
fputs("\n The following monadic predicates have finite extensions: ", stdout);
for (Scan=ana_FINITEMONADICPREDICATES;!list_Empty(Scan);Scan=list_Cdr(Scan)) {
symbol_Print((SYMBOL)list_Car(Scan));
if (!list_Empty(list_Cdr(Scan)))
fputs(", ", stdout);
}
putchar('.');
}
printf("\n Axiom clauses: %d Conjecture clauses: %d",ana_AXIOMCLAUSES,ana_CONCLAUSES);
flag_PrintInferenceRules(Flags);
flag_PrintReductionRules(Flags);
fputs("\n Extras : ", stdout);
if (flag_GetFlagValue(Flags, flag_SATINPUT))
fputs("Input Saturation, ", stdout);
else
fputs("No Input Saturation, ", stdout);
if (flag_GetFlagValue(Flags, flag_SELECT) == flag_SELECTOFF)
fputs("No Selection, ", stdout);
else
if (flag_GetFlagValue(Flags, flag_SELECT) == flag_SELECTIFSEVERALMAXIMAL)
fputs("Dynamic Selection, ", stdout);
else
fputs("Always Selection, ", stdout);
if (flag_GetFlagValue(Flags, flag_SPLITS) == flag_SPLITSUNLIMITED)
fputs("Full Splitting, ", stdout);
else
if (flag_GetFlagValue(Flags, flag_SPLITS) == flag_SPLITSOFF)
fputs("No Splitting, ", stdout);
else
printf("Maximum of %d Splits, ",flag_GetFlagValue(Flags, flag_SPLITS));
if (flag_GetFlagValue(Flags, flag_FULLRED))
fputs("Full Reduction, ", stdout);
else
fputs("Lazy Reduction, ", stdout);
printf(" Ratio: %d, FuncWeight: %d, VarWeight: %d",
flag_GetFlagValue(Flags, flag_WDRATIO),
flag_GetFlagValue(Flags, flag_FUNCWEIGHT),
flag_GetFlagValue(Flags, flag_VARWEIGHT));
fputs("\n Precedence: ", stdout);
fol_PrintPrecedence(Precedence);
fputs("\n Ordering : ", stdout);
fputs(flag_GetFlagValue(Flags, flag_ORD) == flag_ORDKBO ? "KBO" : "RPOS",
stdout);
}
void ana_AutoConfiguration(LIST Clauses, FLAGSTORE Flags,
PRECEDENCE Precedence)
/**************************************************************
INPUT: A list of clauses, a flag store and a precedence.
RETURNS: Nothing.
EFFECT: Based on the values of the ana analysis module, an appropriate
complete configuration of inference, reduction rules and other
settings is established.
***************************************************************/
{
LIST Scan, Functions, Predicates, Constants;
Functions = symbol_GetAllFunctions();
Predicates = fol_GetNonFOLPredicates();
/* Set precedence */
Predicates = ana_CalculatePredicatePrecedence(Predicates, Clauses);
Functions = ana_CalculateFunctionPrecedence(Functions, Clauses, Flags);
Constants = list_Nil();
for (Scan=Functions; !list_Empty(Scan); Scan=list_Cdr(Scan))
if (symbol_IsConstant((SYMBOL)list_Car(Scan)))
Constants = list_Cons(list_Car(Scan),Constants);
Functions = list_NPointerDifference(Functions,Constants);
Constants = list_NReverse(Constants);
for ( ; !list_Empty(Functions); Functions = list_Pop(Functions))
symbol_SetIncreasedOrdering(Precedence, (SYMBOL)list_Car(Functions));
/* Predicates < Functions */
for ( ; !list_Empty(Predicates); Predicates = list_Pop(Predicates))
symbol_SetIncreasedOrdering(Precedence, (SYMBOL)list_Car(Predicates));
/* Constants < Predicates */
/* Predicates < Functions */
for ( ; !list_Empty(Constants); Constants = list_Pop(Constants))
symbol_SetIncreasedOrdering(Precedence, (SYMBOL)list_Car(Constants));
flag_ClearInferenceRules(Flags);
flag_ClearReductionRules(Flags);
flag_SetFlagValue(Flags, flag_ROBV, flag_ROBVON);
flag_SetFlagValue(Flags, flag_RTAUT, flag_RTAUTSYNTACTIC);
flag_SetFlagValue(Flags, flag_RFSUB, flag_RFSUBON);
flag_SetFlagValue(Flags, flag_RBSUB, flag_RBSUBON);
flag_SetFlagValue(Flags, flag_RFMRR, flag_RFMRRON);
flag_SetFlagValue(Flags, flag_RBMRR, flag_RBMRRON);
flag_SetFlagValue(Flags, flag_RUNC, flag_RUNCON);
flag_SetFlagValue(Flags, flag_FULLRED, flag_FULLREDON);
/*flag_SetFlagValue(Flags, flag_FUNCWEIGHT,1);
flag_SetFlagValue(Flags, flag_VARWEIGHT,1);*/
flag_SetFlagValue(Flags, flag_WDRATIO,5);
if (ana_NEQUATIONS) {
flag_SetFlagValue(Flags, flag_IEQR, flag_EQUALITYRESOLUTIONON);
if (ana_NONUNIT) {
if (ana_NONTRIVDOMAIN)
flag_SetFlagValue(Flags, flag_RAED, flag_RAEDPOTUNSOUND);
else
flag_SetFlagValue(Flags, flag_RAED, flag_RAEDSOUND);
}
}
if (ana_PEQUATIONS) {
flag_SetFlagValue(Flags, flag_ISPR, flag_SUPERPOSITIONRIGHTON);
flag_SetFlagValue(Flags, flag_ISPL, flag_SUPERPOSITIONLEFTON);
if (ana_NONHORNCLAUSES > 0)
flag_SetFlagValue(Flags, flag_IEQF, flag_EQUALITYFACTORINGON);
if (ana_NONUNIT)
flag_SetFlagValue(Flags, flag_RCON, flag_RCONON);
flag_SetFlagValue(Flags, flag_RFREW, flag_RFREWON);
flag_SetFlagValue(Flags, flag_RBREW, flag_RBREWON);
flag_SetFlagValue(Flags, flag_RFCRW, flag_RFCRWOFF); /* Here we could activate contextual rewriting */
flag_SetFlagValue(Flags, flag_RBCRW, flag_RBCRWOFF);
}
if (ana_SORTRES) {
flag_SetFlagValue(Flags, flag_SORTS, flag_SORTSMONADICWITHVARIABLE);
flag_SetFlagValue(Flags, flag_IEMS, flag_EMPTYSORTON);
flag_SetFlagValue(Flags, flag_ISOR, flag_SORTRESOLUTIONON);
flag_SetFlagValue(Flags, flag_RSSI, flag_RSSION);
if (!ana_PEQUATIONS || ana_SORTMANYEQUATIONS)
flag_SetFlagValue(Flags, flag_RSST, flag_RSSTON);
}
else
flag_SetFlagValue(Flags, flag_SORTS, flag_SORTSOFF);
if (ana_MONADIC || ana_NONMONADIC) { /* Problem contains real predicates */
flag_SetFlagValue(Flags, flag_IORE, flag_ORDEREDRESOLUTIONNOEQUATIONS);
if (ana_NONHORNCLAUSES > 0)
flag_SetFlagValue(Flags, flag_IOFC, flag_FACTORINGONLYRIGHT);
if (ana_NONUNIT)
flag_SetFlagValue(Flags, flag_RCON, flag_RCONON);
}
if (!ana_FUNCTIONS)
flag_SetFlagValue(Flags, flag_SELECT, flag_SELECTALWAYS);
else
if (ana_NONUNIT)
flag_SetFlagValue(Flags, flag_SELECT, flag_SELECTIFSEVERALMAXIMAL);
else
flag_SetFlagValue(Flags, flag_SELECT, flag_SELECTOFF);
if (ana_CONCLAUSES < ana_AXIOMCLAUSES || (ana_CONGROUND && !ana_PUREPROPOSITIONAL))
flag_SetFlagValue(Flags, flag_SATINPUT, flag_SATINPUTON);
else
flag_SetFlagValue(Flags, flag_SATINPUT, flag_SATINPUTOFF);
if (ana_NONHORNCLAUSES > 0)
flag_SetFlagValue(Flags, flag_SPLITS, flag_SPLITSUNLIMITED);
else
flag_SetFlagValue(Flags, flag_SPLITS, flag_SPLITSOFF);
}
void ana_ExploitSortAnalysis(FLAGSTORE Flags)
/**************************************************************
INPUT: A flag store.
EFFECT: If all equations are many sorted and or no positive
equations occur at all and the problem contains sort
information, static soft typing is activated.
***************************************************************/
{
if (ana_SORTRES && (!ana_PEQUATIONS || ana_SORTMANYEQUATIONS))
flag_SetFlagValue(Flags, flag_RSST, flag_RSSTON);
}
static LIST ana_CalculatePredicatePrecedence(LIST Predicates, LIST Clauses)
/**************************************************************
INPUT: A list of predicates and a list of clauses.
RETURNS: A list of predicate symbols, which should be used
for setting the symbol precedence. The list is sorted
in descending order, that means predicates with highest
precedence come first.
EFFECT: Analyze the clause list to build a directed graph G where
the predicates are vertices. There's an edge (P,Q) in
G iff a clause exists where P is a negative literal
and Q is a positive literal and P != Q. Apply DFS to
find the strongly connected components of this graph.
The <Predicates> list is deleted.
CAUTION: The predicate list must contain ALL predicates
occurring in the clause list!
***************************************************************/
{
GRAPH graph;
LIST result, scan;
int i, j;
NAT count;
SYMBOL s;
/* clause_ListPrint(Clauses); DBG */
if (list_Empty(Predicates)) {
return Predicates;
}
graph = graph_Create();
/* First create the nodes: one node for every predicate symbol. */
for ( ; !list_Empty(Predicates); Predicates = list_Pop(Predicates))
graph_AddNode(graph, symbol_Index((SYMBOL)list_Car(Predicates)));
/* Now scan the clause clause list to create the edges */
/* An edge (P,Q) means P is smaller than Q */
for (scan = Clauses; !list_Empty(scan); scan = list_Cdr(scan)) {
CLAUSE c = list_Car(scan);
for (i = clause_FirstLitIndex(); i < clause_FirstSuccedentLitIndex(c); i++) {
SYMBOL negPred = term_TopSymbol(clause_GetLiteralAtom(c, i));
if (!symbol_Equal(negPred, fol_Equality())) { /* negative predicate */
for (j = clause_FirstSuccedentLitIndex(c); j < clause_Length(c); j++) {
SYMBOL posPred = term_TopSymbol(clause_GetLiteralAtom(c, j));
if (!symbol_Equal(posPred, fol_Equality()) && /* positive predicate */
negPred != posPred) { /* No self loops! */
graph_AddEdge(graph_GetNode(graph, symbol_Index(negPred)),
graph_GetNode(graph, symbol_Index(posPred)));
}
}
}
}
}
/* graph_Print(graph); fflush(stdout); DBG */
/* Calculate the strongly connected components of the graph */
count = graph_StronglyConnectedComponents(graph);
/* Now create the precedence list by scanning the nodes. */
/* If there's a link between two strongly connected components */
/* c1 and c2 then component_num(c1) > component_num(c2), so the */
/* following code creates a valid precedence list in descending */
/* order. */
result = list_Nil();
for (i = count - 1; i >= 0; i--) {
for (scan = graph_Nodes(graph); !list_Empty(scan); scan = list_Cdr(scan)) {
GRAPHNODE n = list_Car(scan);
if (graph_NodeCompNum(n) == i) {
/* The symbol represented by the node <<n> belongs to component <i> */
s = symbol_GetSigSymbol(graph_NodeNumber(n));
result = list_Cons((POINTER)s, result);
}
}
}
/* putchar('\n');
for (scan = result; !list_Empty(scan); scan = list_Cdr(scan)) {
s = (SYMBOL) list_Car(scan);
symbol_Print(s);
putchar(' ');
}
putchar('\n'); fflush(stdout); DBG */
graph_Delete(graph);
return result;
}
/* We use the node info to store the degree of the node */
static __inline__ NAT ana_NodeDegree(GRAPHNODE Node)
{
return (NAT)graph_NodeInfo(Node);
}
static __inline__ void ana_IncNodeDegree(GRAPHNODE Node)
{
graph_NodeSetInfo(Node, (POINTER)(ana_NodeDegree(Node)+1));
}
static BOOL ana_NodeGreater(GRAPHNODE N1, GRAPHNODE N2)
/**************************************************************
INPUT: Two graph nodes.
RETURNS: TRUE, if N1 is greater than N2.
EFFECT: This function is used to sort the node list
of the graph in ana_CalculateFunctionPrecedence.
***************************************************************/
{
return (symbol_Arity(symbol_GetSigSymbol(graph_NodeNumber(N1))) >
symbol_Arity(symbol_GetSigSymbol(graph_NodeNumber(N2))));
}
static BOOL ana_BidirectionalDistributivity(LIST SymbolPairs)
/**************************************************************
INPUT: A list of symbol pairs defining distributivity.
RETURNS: TRUE, if the list contains two pairs (s1, s2) and (s2, s1)
FALSE otherwise.
EFFECT: This function is used to detect symbols that are distributive
in both directions, logical OR and AND for example.
***************************************************************/
{
LIST scan, actPair, nextPair;
for ( ; !list_Empty(SymbolPairs); SymbolPairs = list_Cdr(SymbolPairs)) {
actPair = list_Car(SymbolPairs);
/* If actPair = (s1, s2), check whether there's a pair (s2, s1) in list */
for (scan = list_Cdr(SymbolPairs); !list_Empty(scan); scan = list_Cdr(scan)) {
nextPair = list_Car(scan);
if (symbol_Equal((SYMBOL)list_PairFirst(actPair),(SYMBOL)list_PairSecond(nextPair)) &&
symbol_Equal((SYMBOL)list_PairSecond(actPair),(SYMBOL)list_PairFirst(nextPair)))
return TRUE;
}
}
return FALSE;
}
static LIST ana_CalculateFunctionPrecedence(LIST Functions, LIST Clauses,
FLAGSTORE Flags)
/**************************************************************
INPUT: A list of functions, a list of clauses and
a flag store.
RETURNS: A list of function symbols, which should be used
for setting the symbol precedence. The list is sorted
in descending order, that means function with highest
precedence come first.
EFFECT: Analyzes the clauses to build a directed graph G with
function symbol as nodes. An edge (f,g) or in G means
f should have lower precedence than g.
An edge (f,g) or (g,f) is created if there's an equation
equal(f(...), g(...)) in the clause list.
The direction of the edge depends on the degree of the
nodes and the symbol arity.
Then find the strongly connected components of this
graph.
The "Ordering" flag will be set in the flag store.
CAUTION: The value of "ana_PEQUATIONS" must be up to date.
***************************************************************/
{
GRAPH graph;
GRAPHNODE n1, n2;
LIST result, scan, scan2, distrPairs;
NAT i, j;
SYMBOL s, Add, Mult;
if (list_Empty(Functions))
return Functions; /* Problem contains no functions */
else if (!ana_PEQUATIONS) {
Functions = list_NumberSort(Functions, (NAT (*)(POINTER)) symbol_PositiveArity);
return Functions;
}
graph = graph_Create();
/* First create the nodes: one node for every function symbol. */
for (; !list_Empty(Functions); Functions = list_Pop(Functions))
graph_AddNode(graph, symbol_Index((SYMBOL)list_Car(Functions)));
/* Now sort the node list wrt descending symbol arity. */
graph_SortNodes(graph, ana_NodeGreater);
/* A list of pairs (add, multiply) of distributive symbols */
distrPairs = list_Nil();
/* Now add undirected edges: there's an undirected edge between */
/* two nodes if the symbols occur as top symbols in a positive */
/* equation. */
for (scan = Clauses; !list_Empty(scan); scan = list_Cdr(scan)) {
CLAUSE c = list_Car(scan);
for (i = clause_FirstSuccedentLitIndex(c);
i <= clause_LastSuccedentLitIndex(c); i++) {
if (clause_LiteralIsEquality(clause_GetLiteral(c, i))) {
/* Consider only positive equations */
TERM t1, t2;
if (fol_DistributiveEquation(clause_GetLiteralAtom(c,i), &Add, &Mult)) {
/* Add a pair (Add, Mult) to <distrTerms> */
distrPairs = list_Cons(list_PairCreate((POINTER)Add, (POINTER)Mult),
distrPairs);
/*fputs("\nDISTRIBUTIVITY: ", stdout);
term_PrintPrefix(clause_GetLiteralAtom(c,i));
fputs(" Add=", stdout); symbol_Print(Add);
fputs(" Mult=", stdout); symbol_Print(Mult); fflush(stdout); DBG */
}
t1 = term_FirstArgument(clause_GetLiteralAtom(c, i));
t2 = term_SecondArgument(clause_GetLiteralAtom(c, i));
if (!term_IsVariable(t1) && !term_IsVariable(t2) &&
!term_EqualTopSymbols(t1, t2) && /* No self loops! */
!term_HasSubterm(t1, t2) && /* No subterm property */
!term_HasSubterm(t2, t1)) {
n1 = graph_GetNode(graph, symbol_Index(term_TopSymbol(t1)));
n2 = graph_GetNode(graph, symbol_Index(term_TopSymbol(t2)));
/* Create an undirected edge by adding two directed edges */
graph_AddEdge(n1, n2);
graph_AddEdge(n2, n1);
/* Use the node info for the degree of the node */
ana_IncNodeDegree(n1);
ana_IncNodeDegree(n2);
}
}
}
}
/* putchar('\n');
for (scan = graph_Nodes(graph); !list_Empty(scan); scan = list_Cdr(scan)) {
n1 = list_Car(scan);
printf("(%s,%d,%u), ",
symbol_Name(symbol_GetSigSymbol(graph_NodeNumber(n1))),
graph_NodeNumber(n1), ana_NodeDegree(n1));
}
graph_Print(graph); fflush(stdout); DBG */
graph_DeleteDuplicateEdges(graph);
/* Transform the undirected graph into a directed graph. */
for (scan = graph_Nodes(graph); !list_Empty(scan); scan = list_Cdr(scan)) {
n1 = list_Car(scan);
result = list_Nil(); /* Collect edges from n1 that shall be deleted */
for (scan2 = graph_NodeNeighbors(n1); !list_Empty(scan2);
scan2 = list_Cdr(scan2)) {
int a1, a2;
n2 = list_Car(scan2);
/* Get the node degrees in the undirected graph with multiple edges */
i = ana_NodeDegree(n1);
j = ana_NodeDegree(n2);
a1 = symbol_Arity(symbol_GetSigSymbol(graph_NodeNumber(n1)));
a2 = symbol_Arity(symbol_GetSigSymbol(graph_NodeNumber(n2)));
if (i > j || (i==j && a1 >= a2)) {
/* symbol2 <= symbol1, so remove edge n1 -> n2 */
result = list_Cons(n2, result);
}
if (i < j || (i==j && a1 <= a2)) {
/* symbol1 <= symbol2, so remove edge n2 -> n1 */
graph_DeleteEdge(n2, n1);
}
/* NOTE: If (i==j && a1==a2) both edges are deleted! */
}
/* Now delete edges from n1 */
for ( ; !list_Empty(result); result = list_Pop(result))
graph_DeleteEdge(n1, list_Car(result));
}
if (!list_Empty(distrPairs) && !ana_BidirectionalDistributivity(distrPairs)) {
/* Enable RPO ordering, otherwise the default KBO will be used. */
flag_SetFlagValue(Flags, flag_ORD, flag_ORDRPOS);
}
/* Now examine the list of distribute symbols */
/* since they've highest priority. */
for ( ; !list_Empty(distrPairs); distrPairs = list_Pop(distrPairs)) {
scan = list_Car(distrPairs); /* A pair (Add, Mult) */
/* Addition */
n1 = graph_GetNode(graph,
symbol_Index((SYMBOL)list_PairFirst(scan)));
/* Multiplication */
n2 = graph_GetNode(graph,
symbol_Index((SYMBOL)list_PairSecond(scan)));
/* Remove any edges between n1 and n2 */
graph_DeleteEdge(n1, n2);
graph_DeleteEdge(n2, n1);
/* Add one edge Addition -> Multiplication */
graph_AddEdge(n1, n2);
list_PairFree(scan);
}
/* fputs("\n------------------------",stdout);
graph_Print(graph); fflush(stdout); DBG */
/* Calculate the strongly connected components of the graph. */
/* <i> is the number of SCCs. */
i = graph_StronglyConnectedComponents(graph);
/* Now create the precedence list by scanning the nodes. */
/* If there's a link between two strongly connected components */
/* c1 and c2 then component_num(c1) > component_num(c2), so the */
/* following code creates a valid precedence list in descending */
/* order. */
result = list_Nil();
while (i-- > 0) { /* for i = numberOfSCCs -1 dowto 0 */
for (scan = graph_Nodes(graph); !list_Empty(scan); scan = list_Cdr(scan)) {
n1 = list_Car(scan);
if (graph_NodeCompNum(n1) == i) {
/* The symbol represented by the node <n> belongs to component <i> */
s = symbol_GetSigSymbol(graph_NodeNumber(n1));
result = list_Cons((POINTER)s, result);
}
}
}
/* putchar('\n');
for (scan = result; !list_Empty(scan); scan = list_Cdr(scan)) {
s = (SYMBOL) list_Car(scan);
symbol_Print(s);
fputs(" > ", stdout);
}
putchar('\n'); fflush(stdout); DBG */
graph_Delete(graph);
return result;
}