(* ----------------------------------------------------------------------------
 * $Id: MASLOG.mi,v 1.4 1994/11/28 21:04:08 dolzmann Exp $
 * ----------------------------------------------------------------------------
 * Copyright (c) 1993 Universitaet Passau
 * ----------------------------------------------------------------------------
 * This file is part of MAS.
 * ----------------------------------------------------------------------------
 * $Log: MASLOG.mi,v $
 * Revision 1.4  1994/11/28  21:04:08  dolzmann
 * New revision of the MASLOG system: New functions and bug fixes of old one.
 *
 * Revision 1.3  1993/12/17  17:12:10  dolzmann
 * MASLOG is divided into three parts. (MLOGBASE, MLOGIO, MASLOG)
 * Additional input procedures are added.
 *
 * Revision 1.2  1993/10/03  18:28:02  dolzmann
 * New version of procedure FORMKVD
 *
 * Revision 1.1  1993/07/13  14:44:06  dolzmann
 * The maslog-system and a simple example.
 *
 * ----------------------------------------------------------------------------
 *)

IMPLEMENTATION MODULE MASLOG;
(* Maslog Implementation Module. *)

(******************************************************************************
*				 M A S L O G				      *
*-----------------------------------------------------------------------------*
* Author:   Andreas Dolzmann                                                  *
* Language: MODULA II (mocka or mtc are possible.)                            *
* System:   Program for the computer algebra system MAS by Heinz Kredel.      *
* Project:  MASLOG                                                            *
* Remark:   Libraries maskern, maslisp are used.                              *
* Abstract: A package for the MAS computer algebra system by Heinz Kredel.    *
*           This package implements basic routins on formulas of the first    *
*           order predicate calculus.                                         *
******************************************************************************)

FROM MASBIOS	IMPORT	BLINES, MASORD, SWRITE;
FROM MASELEM	IMPORT	MASREM;
FROM MASERR	IMPORT	ERROR, confusion, fatal, harmless, severe, spotless;
FROM MASLISPU	IMPORT	Declare, PROCF0, PROCF1, PROCF2, PROCF3, PROCP1;
FROM MASSET	IMPORT	SetAddQ, SetComplementQ;
FROM MASSTOR	IMPORT	ADV, COMP, FIRST, INV, LENGTH, LIST, LIST1, RED, SIL;
FROM MASSYM2	IMPORT	ASSOCQ, ENTER, EXPLOD, GENSYM, SREAD, UWRITE; 
FROM MLOGBASE	IMPORT	ANY, BOOL, EQUIV, ET, EXIST, FALSUM, FORALL,
			FORGARGS, FORGLVAR, FORGOP, FORISATOM, FORISBBFOR,
			FORISBOOLVAR, FORISLVAR, FORISVAR, FORMKBINOP,
			FORMKCNST, FORMKFOR, FORMKLVAR, FORMKQUANT,
			FORMKUNOP, FORMKVAR, FORPARGS, FORPBINOP, FORPBINOPA,
			FORPFOR, FORPLVAR, FORPQUANT, FORPQUANTA, FORPUNOP,
			FORPUNOPA, FORPVAR, FORPVARA, FORTST, FORVTENTER,
			FORVTGET, IMP, NON, PROCFB1, PROCFB2, REP, TVAR, VEL,
			VERUM, XOR; 
FROM SACLIST	IMPORT	ADV2, ADV3, AREAD, CCONC, CINV, COMP2, CONC, EQUAL,
			LIST10, LIST2, LIST3, LIST4, LIST5, MEMBER, SECOND,
			THIRD;
			
CONST rcsidi = "$Id: MASLOG.mi,v 1.4 1994/11/28 21:04:08 dolzmann Exp $";
CONST copyrighti = "Copyright (c) 1993 Universitaet Passau";


(******************************************************************************
*			  M A K E   P O S I T I V E			      *
******************************************************************************)

PROCEDURE FORMKPOS(phi, pref: LIST;bbmkneg:PROCF1):LIST;
(* formula make positive. phi is a formula; pref is a symbol of the set \{ET,
VEL, NON\}; bbmkneg is a bb-procedure to negate a bb-formula; a formula
equivalent to phi, which is relative positive, is returned.  Relative positive
means that negations are only in front of atomic formulas. pref is a switch
that controls the substitution of the operators IMP, REP, EQUIV, XOR. If
pref=NON then subformulas with IMP and REP are substituted, only if they are
negated, EQUIV and XOR are not substituted.  If pref=ET or pref=VEL then IMP
and REP are substituted every time.  If pref=ET (pref=VEL) then the outermost
operator of the replacement for EQUIV and XOR is an ET (a VEL) operator. *)
	VAR op, args, vars, formula, posformula, result, key: LIST;
	VAR arg1, arg2, posarg1, posarg2, nposarg1, nposarg2: LIST;
BEGIN
	IF phi = SIL THEN RETURN SIL; END;

	IF (pref<>VEL) AND (pref<>ET) AND (pref<>NON) THEN
		ERROR(severe,"FORMKPOS: wrong preference given (assume NON)");
		pref:=NON;
	END;
	FORPFOR(phi,op,args);
	IF (op=VERUM) OR (op=FALSUM) THEN
		RETURN phi;
	ELSIF op=NON THEN
		FORPUNOPA(args,formula);
		RETURN complement(formula,pref,bbmkneg);
	ELSIF (op=VEL) OR (op=ET) THEN
		result:=SIL;
		WHILE args <> SIL DO
			FORPARGS(args,formula,args);
			posformula:=FORMKPOS(formula,pref,bbmkneg);
			result:=COMP(posformula,result);
		END;
		RETURN FORMKFOR(op,INV(result));
	ELSIF (op=EXIST) OR (op=FORALL) THEN
		FORPQUANTA(args,vars,formula);
		posformula:=FORMKPOS(formula,pref,bbmkneg);
		RETURN FORMKQUANT(op,vars,posformula);
	ELSIF (op=IMP) AND (pref<>NON) THEN
		FORPBINOPA(args,arg1,arg2);
		RETURN FORMKBINOP(VEL,complement(arg1,pref,bbmkneg),
			FORMKPOS(arg2,pref,bbmkneg));
	ELSIF (op=IMP) AND (pref=NON) THEN
		FORPBINOPA(args,arg1,arg2);
		RETURN FORMKBINOP(IMP,FORMKPOS(arg1,pref,bbmkneg),
					FORMKPOS(arg2,pref,bbmkneg));
	ELSIF (op=REP) AND (pref<>NON) THEN
		FORPBINOPA(args,arg1,arg2);
		RETURN FORMKBINOP(VEL,FORMKPOS(arg1,pref,bbmkneg),
			complement(arg2,pref,bbmkneg));
	ELSIF (op=REP) AND (pref=NON) THEN
		FORPBINOPA(args,arg1,arg2);
		RETURN FORMKBINOP(REP,FORMKPOS(arg1,pref,bbmkneg),
					FORMKPOS(arg2,pref,bbmkneg));
	ELSIF (op=EQUIV) AND (pref<>NON) THEN
		FORPBINOPA(args,arg1,arg2);
		posarg1:=FORMKPOS(arg1,pref,bbmkneg);
		posarg2:=FORMKPOS(arg2,pref,bbmkneg);
		nposarg1:=complement(arg1,pref,bbmkneg);
		nposarg2:=complement(arg2,pref,bbmkneg);
		IF pref=ET THEN
			RETURN FORMKBINOP(ET,FORMKBINOP(VEL,nposarg1,posarg2),
				 FORMKBINOP(VEL,posarg1,nposarg2));
		ELSIF pref=VEL THEN
			RETURN FORMKBINOP(VEL,FORMKBINOP(ET,posarg1,posarg2),
				 FORMKBINOP(ET,nposarg1,nposarg2));
		END;
	ELSIF (op=EQUIV) AND (pref=NON) THEN
		FORPBINOPA(args,arg1,arg2);
		RETURN FORMKBINOP(EQUIV,
			FORMKPOS(arg1,pref,bbmkneg),
			FORMKPOS(arg2,pref,bbmkneg));
	ELSIF (op=XOR) AND (pref<>NON) THEN
		FORPBINOPA(args,arg1,arg2);
		posarg1:=FORMKPOS(arg1,pref,bbmkneg);
		posarg2:=FORMKPOS(arg2,pref,bbmkneg);
		nposarg1:=complement(arg1,pref,bbmkneg);
		nposarg2:=complement(arg2,pref,bbmkneg);
		IF pref=VEL THEN
			RETURN FORMKBINOP(VEL,FORMKBINOP(ET,posarg1,nposarg2),
				FORMKBINOP(ET,nposarg1,posarg2));
		ELSIF pref=ET THEN
			RETURN FORMKBINOP(ET,FORMKBINOP(VEL,posarg1,posarg2),
				 FORMKBINOP(VEL,nposarg1,nposarg2));
		END;
	ELSIF (op=XOR) AND (pref=NON) THEN
		FORPBINOPA(args,arg1,arg2);
		RETURN FORMKBINOP(XOR,
			FORMKPOS(arg1,pref,bbmkneg),
			FORMKPOS(arg2,pref,bbmkneg));
	ELSIF op=TVAR THEN
		RETURN phi;
	ELSE
		RETURN phi;
	END;
END FORMKPOS;

PROCEDURE complement(phi, pref: LIST; bbmkneg:PROCF1): LIST;
(* complement. like FORMKPOS, but supposes that phi is negated. *)
	VAR op,args,vars,formula,posformula,result: LIST;
	VAR arg1,arg2, posarg1, posarg2, nposarg1, nposarg2: LIST;
BEGIN
	IF phi = SIL THEN RETURN SIL; END;
	FORPFOR(phi,op,args);
	IF op=VERUM THEN
		RETURN FORMKCNST(FALSUM);
	ELSIF op=FALSUM THEN
		RETURN FORMKCNST(VERUM);
	ELSIF op=NON THEN
		FORPARGS(args,formula,args);
		RETURN FORMKPOS(formula,pref,bbmkneg);
	ELSIF (op=VEL) OR (op=ET) THEN
		result:=SIL;
		WHILE args <> SIL DO
			FORPARGS(args,formula,args);
			posformula:=complement(formula,pref,bbmkneg);
			result:=COMP(posformula,result);
		END;
		RETURN FORMKFOR(notsymbol(op),INV(result));
	ELSIF (op=EXIST) OR (op=FORALL) THEN
		FORPQUANTA(args,vars,formula);
		posformula:=complement(formula,pref,bbmkneg);
		RETURN FORMKQUANT(notsymbol(op),vars,posformula);
	ELSIF op=REP THEN
		FORPBINOPA(args,arg1,arg2);
		posarg1:=complement(arg1,pref,bbmkneg);
		posarg2:=FORMKPOS(arg2,pref,bbmkneg);
		RETURN FORMKBINOP(ET,posarg1,posarg2);
	ELSIF op=IMP THEN
		FORPBINOPA(args,arg1,arg2);
		posarg1:=FORMKPOS(arg1,pref,bbmkneg);
		posarg2:=complement(arg2,pref,bbmkneg);
		RETURN FORMKBINOP(ET,posarg1,posarg2);
	ELSIF (op=XOR) AND (pref<>NON) THEN
		FORPBINOPA(args,arg1,arg2);
		posarg1:=FORMKPOS(arg1,pref,bbmkneg);
		posarg2:=FORMKPOS(arg2,pref,bbmkneg);
		nposarg1:=complement(arg1,pref,bbmkneg);
		nposarg2:=complement(arg2,pref,bbmkneg);
		IF pref=ET THEN
			RETURN FORMKBINOP(ET,FORMKBINOP(VEL,posarg1,nposarg2),
				 FORMKBINOP(VEL,nposarg1,posarg2));
		ELSIF pref=VEL THEN
			RETURN FORMKBINOP(VEL,FORMKBINOP(ET,posarg1,posarg2),
				 FORMKBINOP(ET,nposarg1,nposarg2));
		END;
	ELSIF (op=XOR) AND (pref=NON) THEN
		FORPBINOPA(args,arg1,arg2);
		RETURN FORMKBINOP(EQUIV,
			FORMKPOS(arg1,pref,bbmkneg),
			FORMKPOS(arg2,pref,bbmkneg));
	ELSIF (op=EQUIV) AND (pref<>NON) THEN
		FORPBINOPA(args,arg1,arg2);
		posarg1:=FORMKPOS(arg1,pref,bbmkneg);
		posarg2:=FORMKPOS(arg2,pref,bbmkneg);
		nposarg1:=complement(arg1,pref,bbmkneg);
		nposarg2:=complement(arg2,pref,bbmkneg);
		IF pref=VEL THEN
			RETURN FORMKBINOP(VEL,FORMKBINOP(ET,posarg1,nposarg2),
				 FORMKBINOP(ET,nposarg1,posarg2));
		ELSIF pref=ET THEN
			RETURN FORMKBINOP(ET,FORMKBINOP(VEL,posarg1,posarg2),
				 FORMKBINOP(VEL,nposarg1,nposarg2));
		END;
	ELSIF (op=EQUIV) AND (pref=NON) THEN
		FORPBINOPA(args,arg1,arg2);
		RETURN FORMKBINOP(XOR,
			FORMKPOS(arg1,pref,bbmkneg),
			FORMKPOS(arg2,pref,bbmkneg));
	ELSIF op=TVAR THEN
		RETURN FORMKUNOP(NON,phi);
	ELSE
		RETURN bbmkneg(phi);
	END;
END complement;


(******************************************************************************
*	    M A K E   D I S J U N C T I V E   N O R M A L F O R M	      *
******************************************************************************)

PROCEDURE FORMKDNF(phi: LIST; bbmkneg: PROCF1): LIST;
(* formula make dnf. phi is a quantifier-free formula, bbmkneg is a
bb-pro\-ce\-dure to negate a bb-formula; a formula phi1 equivalent to phi is
returned.  phi1 is in strict dnf. *)
BEGIN
	RETURN FORMKDNF1(phi, bbmkneg, FALSE);
END FORMKDNF;

PROCEDURE FORMKDNF1(phi: LIST; bbmkneg: PROCF1; neg: BOOLEAN): LIST;
(* formula make postiv 1. phi is a quantifier-free formula; bbmkneg is a
bb-procedure to negate a bb-formula, neg is a flag that shows whether a
negation was read or not; FORMKDNF1 returns an equivalent formula in strict
dnf. *)
	VAR op, red, arg, arg1, arg2, dnfarg, result, opvel, psi, prednf: LIST;
BEGIN
	IF phi=SIL THEN RETURN SIL; END;

	FORPFOR(phi,op,red);
	IF (op=VERUM) OR (op=FALSUM) THEN
		IF neg 	THEN
			RETURN FORMKUNOP(VEL,
				FORMKUNOP(ET,notsymbol(phi)));
		ELSE
			RETURN FORMKUNOP(VEL,FORMKUNOP(ET,phi));
		END;
	ELSIF op=NON THEN
		FORPUNOPA(red,arg);
		RETURN FORMKDNF1(arg,bbmkneg,NOT neg);
	ELSIF ((op=VEL) AND (NOT neg)) OR ((op=ET) AND neg) (* VEL *) 	THEN
		(* transform all arguments in dnf and join all disjunctions *)
		result:=SIL;
		WHILE red <> SIL DO
			FORPARGS(red,arg,red);
			dnfarg:=FORMKDNF1(arg,bbmkneg,neg);
			FORPARGS(dnfarg,opvel,psi);
			result:=CCONC(result,psi);
		END;
		RETURN FORMKFOR(VEL,result);
	ELSIF ((op=ET) AND (NOT neg)) OR ((op=VEL) AND neg) (* ET *) THEN
		(* transform all arguments in dnf ... *)
		prednf:=SIL;
		WHILE red <> SIL DO
			FORPARGS(red,arg,red);
			prednf:=COMP(FORMKDNF1(arg,bbmkneg,neg),prednf);
		END;
		RETURN distribetovel(INV(prednf));
	ELSIF op=IMP THEN
		FORPBINOPA(red,arg1,arg2);
		RETURN FORMKDNF1(FORMKBINOP(VEL,FORMKUNOP(NON,arg1),arg2),
			bbmkneg,neg);
	ELSIF op=REP THEN
		FORPBINOPA(red,arg1,arg2);
		RETURN FORMKDNF1(FORMKBINOP(VEL,arg1,FORMKUNOP(NON,arg2)),
			bbmkneg,neg);
	ELSIF ((op=EQUIV) AND (NOT neg)) OR ((op=XOR) AND neg) THEN
		FORPBINOPA(red,arg1,arg2);
		RETURN FORMKDNF1(FORMKBINOP(VEL,
			FORMKBINOP(ET,
				FORMKUNOP(NON,arg1),FORMKUNOP(NON,arg2)),
			FORMKBINOP(ET,arg1,arg2)),bbmkneg,FALSE);
	ELSIF ((op=XOR) AND (NOT neg)) OR ((op=EQUIV) AND neg) THEN
		FORPBINOPA(red,arg1,arg2);
		RETURN FORMKDNF1(FORMKBINOP(VEL,
			FORMKBINOP(ET,arg1,FORMKUNOP(NON,arg2)),
			FORMKBINOP(ET,FORMKUNOP(NON,arg1),arg2)),
			bbmkneg,FALSE);
	ELSIF op=TVAR THEN
		IF neg THEN
			RETURN FORMKUNOP(VEL,FORMKUNOP(ET,FORMKUNOP(NON,phi)));
		ELSE
			RETURN FORMKUNOP(VEL,FORMKUNOP(ET,phi));
		END;
	ELSE
		IF neg THEN
			RETURN FORMKUNOP(VEL,
				FORMKUNOP(ET,bbmkneg(phi)));
		ELSE
			RETURN FORMKUNOP(VEL,FORMKUNOP(ET,phi));
		END;
	END;
END FORMKDNF1;

PROCEDURE distribetovel(L: LIST): LIST;
(* distributive et over vel. L is a list of boolean terms in strict dnf; a
boolean term t equivalent to ET(L) is returned. t is in strict dnf. *)
	VAR first, firstpt, tail, elem, redelem, obj, result, prefix: LIST;
	VAR dummy: LIST;
BEGIN
	IF L = SIL THEN RETURN SIL; END;

	FORPFOR(L,first,tail);
	IF tail = SIL THEN
		RETURN first;
	END;
	FORPARGS(first,dummy,first);
	WHILE tail <> SIL DO
		FORPARGS(tail,obj,tail);
		FORPARGS(obj,dummy,obj);
		result:=SIL;
		WHILE obj <> SIL DO
			FORPARGS(obj,elem,obj);
			redelem:=RED(elem);
			firstpt:=first;
			WHILE firstpt <> SIL DO
				FORPARGS(firstpt,prefix,firstpt);
				result:=COMP(CCONC(prefix,redelem),result);
			END;
		END;
		first:=result;
	END;
	result:=FORMKFOR(VEL,result);
	RETURN result;
END distribetovel;


(******************************************************************************
*	    M A K E   C O N J U N C T I V E   N O R M A L   F O R M           *
******************************************************************************)

PROCEDURE FORMKCNF(phi: LIST; bbmkneg: PROCF1): LIST;
(* formula make cnf. phi is a quantifier-free formula, bbmkneg is a
bb-pro\-ce\-dure to negate a bb-formula; a formula phi1 equivalent to phi is
returned.  phi1 is in strict cnf. *)
BEGIN
	RETURN FORMKCNF1(phi, bbmkneg, FALSE);
END FORMKCNF;

PROCEDURE FORMKCNF1(phi: LIST; bbmkneg: PROCF1; neg: BOOLEAN): LIST;
(* formula make cnf 1. phi is a quantifier-free formula, bbmkneg is a
bb-procedure to negate a bb-formula positive, neg is a flag, that shows
whether a negation was read or not; FORMKCNF1 returns an equivalent formula in
strict cnf. *)
	VAR op, red, arg, arg1, arg2, cnfarg, result, opet, psi, precnf: LIST;
BEGIN
	IF phi=SIL THEN RETURN SIL; END;

	FORPFOR(phi,op,red);
	IF (op=VERUM) OR (op=FALSUM) THEN
		IF neg 	THEN
			RETURN FORMKUNOP(ET,
				FORMKUNOP(VEL,notsymbol(op)));
		ELSE
			RETURN FORMKUNOP(ET,FORMKUNOP(VEL,phi));
		END;
	ELSIF op=NON THEN
		FORPUNOPA(red,arg);
		RETURN FORMKCNF1(arg,bbmkneg,NOT neg);
	ELSIF ((op=ET) AND (NOT neg)) OR ((op=VEL) AND neg)  (* op=ET *) THEN
		(* transform all arguments in cnf and join all disjunctions *)
		result:=SIL;
		WHILE red <> SIL DO
			FORPARGS(red,arg,red);
			cnfarg:=FORMKCNF1(arg,bbmkneg,neg);
			FORPARGS(cnfarg,opet,psi);
			result:=CCONC(result,psi);
		END;
		RETURN FORMKFOR(ET,result);
	ELSIF ((op=VEL) AND (NOT neg)) OR ((op=ET) AND neg)  (* op=VEL *) THEN
		(* transform all arguments in cnf ... *)
		precnf:=SIL;
		WHILE red <> SIL DO
			FORPARGS(red,arg,red);
			precnf:=COMP(FORMKCNF1(arg,bbmkneg,neg),precnf);
		END;
		RETURN distribveloet(INV(precnf));
	ELSIF op=IMP THEN
		FORPBINOPA(red,arg1,arg2);
		RETURN FORMKCNF1(FORMKBINOP(VEL,FORMKUNOP(NON,arg1),arg2),
			bbmkneg,neg);
	ELSIF op=REP THEN
		FORPBINOPA(red,arg1,arg2);
		RETURN FORMKCNF1(FORMKBINOP(VEL,arg1,FORMKUNOP(NON,arg2)),
			bbmkneg,neg);
	ELSIF ((op=XOR) AND (NOT neg)) OR ((op=EQUIV) AND neg) THEN
		FORPBINOPA(red,arg1,arg2);
		RETURN FORMKCNF1(FORMKBINOP(ET,
			FORMKBINOP(VEL,
				FORMKUNOP(NON,arg1),FORMKUNOP(NON,arg2)),
			FORMKBINOP(VEL,arg1,arg2)),bbmkneg,FALSE);
	ELSIF ((op=EQUIV) AND (NOT neg)) OR ((op=XOR) AND neg) THEN
		FORPBINOPA(red,arg1,arg2);
		RETURN FORMKCNF1(FORMKBINOP(ET,
			FORMKBINOP(VEL,arg1,FORMKUNOP(NON,arg2)),
			FORMKBINOP(VEL,FORMKUNOP(NON,arg1),arg2)),
			bbmkneg,FALSE);
	ELSIF op=TVAR THEN
		IF neg 	THEN
			RETURN FORMKUNOP(ET,FORMKUNOP(VEL,FORMKUNOP(NON,phi)));
		ELSE
			RETURN FORMKUNOP(ET,FORMKUNOP(VEL,phi));
		END;
	ELSE
		IF neg 	THEN
			RETURN FORMKUNOP(ET,
				FORMKUNOP(VEL,bbmkneg(phi)));
		ELSE
			RETURN FORMKUNOP(ET,FORMKUNOP(VEL,phi));
		END;
	END;
END FORMKCNF1;

PROCEDURE distribveloet(L: LIST): LIST;
(* distributive vel over et. L is a list of quantifier-free formulas in strict
cnf; a quantifier-free formula equivalent to VEL(L), which is in strict cnf,
is returned. *)
	VAR first, firstpt, tail, elem, redelem, obj, result, prefix: LIST;
	VAR dummy: LIST;
BEGIN
	IF L = SIL THEN RETURN SIL; END;

	FORPFOR(L,first,tail);
	IF tail = SIL THEN
		RETURN first;
	END;
	FORPARGS(first,dummy,first);
	WHILE tail <> SIL DO
		FORPARGS(tail,obj,tail);
		FORPARGS(obj,dummy,obj);
		result:=SIL;
		WHILE obj <> SIL DO
			FORPARGS(obj,elem,obj);
			redelem:=RED(elem);
			firstpt:=first;
			WHILE firstpt <> SIL DO
				FORPARGS(firstpt,prefix,firstpt);
				result:=COMP(CCONC(prefix,redelem),result);
			END;
		END;
		first:=result;
	END;
	result:=FORMKFOR(ET,result);
	RETURN result;
END distribveloet;


(******************************************************************************
*			    M A K E   P R E N E X			      *
******************************************************************************)

PROCEDURE FORMKPRENEX(phi,pref:LIST): LIST;
(* formula make prenex. phi is a formula; pref is an element of \{EXIST,
FORALL\}; a formula psi in prenex normal form is returned.  phi must be a
relative positive formula without additional operation symbols like IMP, REP,
etc.  All bound variables in phi must have different specifications (i.e.
different names or different types).  The only transformation which is used to
calculate psi is the interchange of a junctor with a quantifier.  The formula
psi has the minimal number of blocks of quantifiers under all prenex formulas
which are built using only the interchange of a junctor with a quantifier.
The argument pref is only respected, if there are two equivalent formulas with
the same optimal number of blocks of quantifiers.  In this case the formula is
returned which has a "pref"-quantifier as the outermost operation symbol.*)
	VAR pnfs, phi1, phi2, qbphi1, qbphi2: LIST;
BEGIN
	IF (pref<>EXIST) AND (pref<>FORALL) THEN
		ERROR(severe,
			"FORMKPRENEX: wrong preference given (assume EXIST)");
		pref:=EXIST;
	END;
	pnfs:=FORMKPRENEX1(phi);
	IF RED(pnfs)=SIL THEN
		(* Only one element: No choice is possible. *)
		RETURN FIRST(FIRST(pnfs));
	END;
	phi1:=FIRST(FIRST(pnfs));
	phi2:=FIRST(SECOND(pnfs));
	qbphi1:=SECOND(FIRST(pnfs));
	qbphi2:=SECOND(SECOND(pnfs));
	(* Choice resp. number of blocks of quantifiers. *)
	IF qbphi1<qbphi2 THEN
		RETURN phi1;
	ELSIF qbphi1>qbphi2 THEN
		RETURN phi2;
	(* Choice resp. the preferd type of quantifier. *)
	ELSIF FORGOP(phi1)=pref THEN
		RETURN phi1;
	ELSE
		RETURN phi2;
	END;
END FORMKPRENEX;

PROCEDURE FORMKPRENEXI(phi,pref:LIST): LIST;
(* formula make prenex. phi is a formula; pref is an element of \{EXIST,
FORALL\}; a formula psi in prenex normal form is returned.  phi must be a
relative positive formula without additional operation symbols like IMP, REP,
etc.  All bound variables in phi must have different specifications (i.e.
different names or different types).  The only transformation which is used to
calculate psi is the interchange of a junctor with a quantifier.  The formula
psi has the minimal number of blocks of quantifiers under all prenex formulas
which are built using only the interchange of a junctor with a quantifier.
The argument pref is only respected, if there are two equivalent formulas with
the same optimal number of blocks of quantifiers.  In this case the formula is
returned which has a "pref"-quantifier as the innermost operation symbol.*)
	VAR pnfs, phi1, phi2, qbphi1, qbphi2: LIST;
BEGIN
	IF (pref<>EXIST) AND (pref<>FORALL) THEN
		ERROR(severe,
			"FORMKPRENEX: wrong preference given (assume EXIST)");
		pref:=EXIST;
	END;
	pnfs:=FORMKPRENEX1(phi);
	IF RED(pnfs)=SIL THEN
		(* Only one element: No choice is possible. *)
		RETURN FIRST(FIRST(pnfs));
	END;
	phi1:=FIRST(FIRST(pnfs));
	phi2:=FIRST(SECOND(pnfs));
	qbphi1:=SECOND(FIRST(pnfs));
	qbphi2:=SECOND(SECOND(pnfs));
	(* Choice resp. number of blocks of quantifiers. *)
	IF qbphi1<qbphi2 THEN
		RETURN phi1;
	ELSIF qbphi1>qbphi2 THEN
		RETURN phi2;
	(* Choice resp. the preferd type of quantifier. *)
	ELSIF FORIMQB(phi1)=pref THEN
		RETURN phi1;
	ELSE
		RETURN phi2;
	END;
END FORMKPRENEXI;

PROCEDURE FORMKPRENEX1(phi: LIST): LIST;
(* formula make prenex 1. phi is a relative positive formula; this procedure
returns a list of maximal two objects of the form (psi,qb(psi)). In
(psi,qb(psi)) psi is a formula in prenex normal form, and qb(psi) the number
of blocks of quantifiers.  If there are two objects in the returned list, then
the outermost quantifier of the first formula is an exist quantifier and the
outermost quantifier of the second formula is a forall quantifier.  In the
following comments such a list is called pnf-selection. *)
	VAR op, res: LIST;
BEGIN
	FORPFOR(phi,op,res);
	IF (op=EXIST) OR (op=FORALL) THEN
		RETURN pnfquantifier(phi)
	ELSIF (op=VEL) OR (op=ET) THEN
		RETURN pnfjunctor(phi);
	ELSE  	(* i.e. phi is an atomic formula,
		   but not necessary a bb-formula.
		   VERUM, FALSUM, or a bb-formula, (which are
		   eventually negated) are possible. *)
		RETURN LIST1(LIST2(phi,0))
	END;
END FORMKPRENEX1;

PROCEDURE pnfquantifier(phi:LIST): LIST;
(* prenex normal form quantifier. phi is a relative positive formula with an
quantifier as the outermost operator symbol; pnfquantifier returns a
pnf-selection with only one formula equivalent to phi. *)
	VAR pnfs, qf, vars, nvars, qform, psi1, psi2, qbpsi1, qbpsi2: LIST;
BEGIN
	FORPQUANT(phi,qf,vars,qform);
	nvars:=FORGLVAR(vars);
	pnfs:=FORMKPRENEX1(qform);
	psi1:=FIRST(FIRST(pnfs));
	qbpsi1:=SECOND(FIRST(pnfs));
	IF RED(pnfs)=SIL THEN (* #pnfs=1 *)
		RETURN LIST1(mkquant(qf,nvars,psi1,qbpsi1));
	ELSIF FORGOP(psi1)=qf THEN
		RETURN LIST1(mkquant(qf,nvars,psi1,qbpsi1));
	ELSE
		psi2:=FIRST(SECOND(pnfs));
		qbpsi2:=SECOND(SECOND(pnfs));
		RETURN LIST1(mkquant(qf,nvars,psi2,qbpsi2));
	END;
END pnfquantifier;

PROCEDURE mkquant(qf,vars,phi,qbqform: LIST): LIST;
(* make quantifier. qf is a quantifier; vars is a list of the bound
variables of qf; phi is a formula; qbqform is the number of blocks of
quantifiers of qform, mkquantifier returns a pnf-selection with formulas
equivalent to the formula 'qf vars: phi'. If phi is a quantified formula and
the outermost quantifier of phi is a qf quantifier then mkquant generates no
new quantifier, but bounds the variables var to the outermost quantifier of
phi. *)
	VAR op,res,form,newvarlist, varlist:LIST;
BEGIN
	FORPFOR(phi,op,res);
	IF op<>qf THEN
		RETURN LIST2(FORMKQUANT(qf,FORMKLVAR(vars),phi),qbqform+1);
	ELSE
		FORPQUANTA(res,varlist,form);
		newvarlist:=CCONC(vars,FORGLVAR(varlist));
		RETURN LIST2(FORMKQUANT(qf,FORMKLVAR(newvarlist),form),
			qbqform);
	END;
END mkquant;

PROCEDURE pnfjunctor(phi: LIST):LIST;
(* prenex normal form junctor. phi is a relative positive formula with an ET
or VEL operator as the outermost function symbol; pnfjunctor returns a
pnf-selection with formulas equivalent to phi. If there are two objects in the
pnf-selection, then the outermost quantifier of the formula in the first
(second) object is an EXIST (FORALL) quantifier *)
	VAR op, res, arglist, pnfargs, arg, l1, l2, M, qf1, qf2:LIST;
	VAR phi1, qbphi1, phi2, qbphi2: LIST;
	VAR onlyex, onlyfa: BOOLEAN;
BEGIN
	M:=0;
	onlyex:=TRUE;
	onlyfa:=TRUE;

	FORPFOR(phi,op,res);
	arglist:=SIL;
	l1:=SIL;
	l2:=SIL;
	WHILE res<>SIL DO
		FORPARGS(res,arg,res);
		pnfargs:=FORMKPRENEX1(arg);
		phi1:=FIRST(FIRST(pnfargs));
		qbphi1:=SECOND(FIRST(pnfargs));
		(* calculate the characteristic selections *)
		IF RED(pnfargs)=SIL THEN
			l1:=COMP(phi1,l1);
			l2:=COMP(phi1,l2);
			phi2:=phi1;
			qbphi2:=qbphi1;
		ELSE
			phi2:=FIRST(SECOND(pnfargs));
			qbphi2:=SECOND(SECOND(pnfargs));
			(* In resp. to the definition of pnf is the outermost
			* quantifier of phi1 (phi2) is an EXIST (FORALL)
			* quantifier *)
			l1:=COMP(phi1,l1);
			l2:=COMP(phi2,l2);
		END;
		(* compute the maximum of blocks of quantifiers,
		* simultaneous
		* ascertaian criterions which characteristic selection is
		* optimal resp. the number of blocks of quantifiers. *)
		qf1:=FORGOP(phi1);
		qf2:=FORGOP(phi2);
		IF M<qbphi1 THEN
			M:=qbphi1;
			onlyex:=TRUE;
			onlyfa:=TRUE;
		END;
		IF (M=qbphi1) AND (qf1<>EXIST)  (* for M=0  meaningless *)
		THEN 				(* but M=0 is a special *)
			onlyex:=FALSE;		(* case.		*)
		END;
		IF (M=qbphi2) AND (qf2<>FORALL)	(*        dito       *)
		THEN
			onlyfa:=FALSE
		END;
	END;
	IF M=0 THEN
		RETURN LIST1(LIST2(phi,0));
	END;
	(* Calculate the result with respect to onlyex and onlyfa. *)
	(* refere to the proof in the documentation. *)
	IF onlyex AND (NOT onlyfa) THEN
		RETURN LIST1(interchange(l1,op,EXIST));
	ELSIF onlyfa AND (NOT onlyex) THEN
		RETURN LIST1(interchange(l2,op,FORALL));
	ELSE
		RETURN LIST2(interchange(l1,op,EXIST),
			interchange(l2,op,FORALL));
	END;
END pnfjunctor;

PROCEDURE interchange(L,op,pref:LIST):LIST;
(* interchange. L is a list of relative positive formulas; op is an operation
symbol (VEL or ET); pref is a quantifier symbol; interchange returns an element
of a pnf-selection with a formula equivalent to the formula 'op(L)'. pref is
the type of the outermost quantifier after the interchange, if a choice is
possible. *)
	VAR l1, l2, qf, q, form, qblock, vblock, qform, vars: LIST;
 	VAR varlist, result, numqfb, nextop:LIST;
	VAR noqf: BOOLEAN;
BEGIN
	IF L=SIL THEN RETURN SIL; END;

	l1:=L;
	qf:=pref;
	qblock:=SIL;	(* List of all quantifiers in the blocks *)
	vblock:=SIL;	(* List of all bound variables in the blocks *)
	REPEAT
		l2:=SIL;
		varlist:=SIL;
		noqf:=TRUE;
		WHILE l1<>SIL DO
			ADV(l1,form,l1);
			getqfb(form,qf,vars,qform);
			nextop:=FORGOP(qform);
			noqf:=noqf AND ((nextop<>EXIST) AND (nextop<>FORALL));
			l2:=COMP(qform,l2);
			varlist:=CCONC(varlist,vars);
		END;
		IF varlist <> SIL THEN
			qblock:=COMP(qf,qblock);
			vblock:=COMP(FORMKLVAR(varlist),vblock);
		END;
		l1:=l2;
		qf:=notsymbol(qf);
	UNTIL noqf; (* i.e there are no quantifiers in the formulas of L *)
	(* generate the result *)
	numqfb:=LENGTH(vblock);
	result:=FORMKFOR(op,l1);
	WHILE qblock <> SIL DO
		ADV(qblock,q,qblock);
		ADV(vblock,varlist,vblock);
		result:=FORMKQUANT(q,varlist,result);
	END;
	RETURN LIST2(result,numqfb);
END interchange;

PROCEDURE getqfb(phi,qf: LIST; VAR qfb, qform: LIST);
(* get quantifier block. phi is a relative positive formula; qf is a
quantifier symbol.  qfb is assigned to a list of variables which are bound
to the outermost quantifier of type qf, qform is the formula bound by the
quantifier qf. *)
	VAR op, res, varlist, bound: LIST;
BEGIN
	qfb:=SIL;
	FORPFOR(phi,op,res);
	IF op<>qf THEN
		qform:=phi;
		RETURN;
	END;
	WHILE (op=qf) DO
 		FORPQUANTA(res,varlist,qform);
		FORPLVAR(varlist,bound);
		qfb:=CCONC(qfb,bound);
		FORPFOR(qform,op,res);
	END;
	RETURN;
END getqfb;

PROCEDURE FORIMQB(phi: LIST):LIST;
(* formula innermost quantifier block. phi is a formula in prenex normal form.
If the outermost operator of phi is no quantifier then SIL is returned. 
Otherwise the type of the innermost quantifier block (either FOREX or FORALL) 
is returned. *)
	VAR sym, vars, imq : LIST;
BEGIN
	sym:=FORGOP(phi);
	IF (sym<>EXIST) AND (sym<>FORALL) THEN RETURN SIL; END;
	REPEAT 
		imq:=sym;
		FORPQUANT(phi,sym,vars,phi);
	UNTIL (sym<>EXIST) AND (sym<>FORALL);
	RETURN imq;
END FORIMQB;

(******************************************************************************
*		S U B S T I T U T E   V A R I A B L E                         *
******************************************************************************)

PROCEDURE FORSUBSTVAR(phi, old, new: LIST; bbsubstvar: PROCF3): LIST;
(* formula substitute variable. phi is a formula; old and new are variables; a
formula in which the variable old is substituted by the variable new is
returned. *)
	VAR op, res, arg, arg1, arg2: LIST;
	VAR parlist, lvar, varlist, var, qform: LIST;
BEGIN
	FORPFOR(phi,op,res);

	IF (op=VERUM) OR (op=FALSUM) THEN
		RETURN phi;
	ELSIF op=NON THEN
		FORPUNOPA(res,arg);
		RETURN FORMKUNOP(op,FORSUBSTVAR(arg,old,new,bbsubstvar));
	ELSIF (op=VEL) OR (op=ET) THEN
		parlist:=SIL;
		WHILE res<>SIL DO
			FORPARGS(res,arg,res);
			parlist:=COMP(FORSUBSTVAR(arg,old,new,bbsubstvar),
				parlist);
		END;
		RETURN FORMKFOR(op,INV(parlist));
	ELSIF (op=REP) OR (op=IMP) OR (op=EQUIV) OR (op=XOR) THEN
		FORPBINOPA(res,arg1,arg2);
		RETURN FORMKBINOP(op,
			FORSUBSTVAR(arg1,old,new,bbsubstvar),
			FORSUBSTVAR(arg2,old,new,bbsubstvar));
	ELSIF op=TVAR THEN
		IF EQUAL(phi,old)=1 THEN
			RETURN new;
		ELSE    
			RETURN phi;
		END;       
	ELSIF (op=EXIST) OR (op=FORALL) THEN
		FORPQUANTA(res,lvar,qform);
		FORPLVAR(lvar,varlist);
		parlist:=SIL;
		WHILE varlist<>SIL DO
			FORPARGS(varlist,var,varlist);
			IF EQUAL(var,old)=1 THEN
				parlist:=COMP(new,varlist);
			ELSE
				parlist:=COMP(var,parlist);
			END;
		END;
		RETURN FORMKQUANT(op,FORMKLVAR(INV(parlist)),
			FORSUBSTVAR(qform,old,new,bbsubstvar));
	ELSE
		RETURN bbsubstvar(phi,old,new);
	END;
END FORSUBSTVAR;


(******************************************************************************
*		 M A K E   V A R I A B L E S   D I S J O I N T                *
******************************************************************************)

PROCEDURE FORMKVD(phi:LIST; bbsubstvar:PROCF3;bblsvars:PROCF1): LIST;
(* formula make variable names disjoint. phi is a formula, bbsubstvar is a
bb-procedure to substitute variables in bb-formulas, bblsvars is a
bb-procedure to list all variables in a bb-formula; FORMKVD returns a formula
in which all bound variables of the same sort have different names. Only the
minimal number of renamings are done to make the names different. *)
	VAR all,used,var,xall,name,sort,free,bound,env: LIST;
BEGIN
	free:=SIL;
	bound:=SIL;
	env:=SIL;
	collectnames(phi,env,bblsvars,free,bound);
	used:=free;
	all:=CCONC(free,bound);
	xall:=SIL;
	WHILE all<>SIL DO
		ADV(all,var,all);
		FORPVAR(var,name,sort);
		xall:=COMP(LIST2(FORVTGET(name),FORVTGET(sort)),xall);
	END;
	RETURN repvar(phi,SIL,SIL,used,xall,bbsubstvar);
END FORMKVD;

PROCEDURE collectnames(phi,env:LIST; bblsvars:PROCF1; VAR free, bound:LIST);
(* collect names. phi is a formula, env is the list of all bound variables
in phi; bblsvars is a bb-procedure to list all variables in a bb-formula; 
the list of all free (bound) varaiables of phi are built in the list free 
(bound). 
It should be taken into account that one variable can occure in the list free
and in the list bound! *)
	VAR op, red, arg, arg1, arg2, lvar, psi, name, sort: LIST;
	VAR varlist, var: LIST;
BEGIN
	IF phi=SIL THEN RETURN;  END;

	FORPFOR(phi,op,red);
	IF (op=VERUM) OR (op=FALSUM) THEN
		RETURN ;
   	ELSIF op=NON THEN
		FORPUNOPA(red,arg);
		collectnames(arg,env,bblsvars,free,bound);
		RETURN;
   	ELSIF (op=VEL) OR (op=ET) THEN
		WHILE red<>SIL DO
			FORPARGS(red,arg,red);
			collectnames(arg,env,bblsvars,free,bound);
   		END;
		RETURN ;
	ELSIF (op=IMP) OR (op=REP) OR (op=EQUIV) OR (op=XOR) THEN
		FORPBINOPA(red,arg1,arg2);
		collectnames(arg1,env,bblsvars,free,bound);
		collectnames(arg2,env,bblsvars,free,bound);
		RETURN;
	ELSIF (op=EXIST) OR (op=FORALL) THEN
		FORPQUANTA(red,lvar,psi);
		varlist:=FORGLVAR(lvar);
		env:=CCONC(varlist,env);
		bound:=CCONC(varlist,bound);
		collectnames(psi,env,bblsvars,free,bound);
		RETURN;
	ELSIF (op=TVAR) (* sort = BOOL *) THEN
		free:=COMP(phi,free);	(* regard boolean vars as free vars *)
		RETURN;
	ELSE  (* phi is an atomic formula *)
		varlist:=SetComplementQ(env,bblsvars(phi));
		free:=CCONC(varlist,free);
		RETURN;
	END;
END collectnames;

PROCEDURE repvar(phi,old,new:LIST; VAR used, denied: LIST;
	bbsubstvar: PROCF3):LIST;
(* replace variables. phi is a formula; old is a list of variables which are
substituted with the corresponding variables in new; used is list of variables
of phi which are already used (and contains also the names of all free 
varaiables; denied is a list of lists of the form (name,sort). 
The list denied describes a list of variables which are not
allowed to be generated. 
The procedure bbsubstvar is a bb-procedure to substitute variables in 
bb-formulas. repvar returns a formula in which the variables are replaced; 
used and denied are updated. *)
	VAR op, red, arg, arg1, arg2, lvar, psi, name, newvars, newv,
		sort, result, vars, v, p, t: LIST;
BEGIN
	IF phi=SIL THEN RETURN SIL; END;

	FORPFOR(phi,op,red);
	IF (op=VERUM) OR (op=FALSUM) THEN
		RETURN phi;
   	ELSIF op=NON THEN
		FORPUNOPA(red,arg);
		RETURN FORMKUNOP(NON,
			repvar(arg,old,new,used,denied,bbsubstvar));
   	ELSIF (op=VEL) OR (op=ET) THEN
		result:=SIL;
		WHILE red<>SIL DO
			FORPARGS(red,arg,red);
			result:=COMP(repvar(arg,old,new,used,denied,
					 bbsubstvar),result);
   		END;
		RETURN FORMKFOR(op,INV(result));
	ELSIF (op=IMP) OR (op=REP) OR (op=EQUIV) OR (op=XOR) THEN
		FORPBINOPA(red,arg1,arg2);
		RETURN FORMKBINOP(op,
			repvar(arg1,old,new,used,denied,bbsubstvar),
			repvar(arg2,old,new,used,denied,bbsubstvar))
	ELSIF (op=EXIST) OR (op=FORALL) THEN
		FORPQUANTA(red,lvar,psi);
		FORPLVAR(lvar,vars);
		newvars:=SIL;
		WHILE vars<>SIL DO
			ADV(vars,v,vars);
			IF MEMBER(v,used)=1
			THEN
				newv:=GENVAR(v,denied);
				FORPVAR(newv,name,sort);
				denied:=COMP(LIST2(FORVTGET(name),
					FORVTGET(sort)),denied); 
				old:=COMP(v,old);
				new:=COMP(newv,new);
				newvars:=COMP(newv,newvars);
			ELSE
				used:=COMP(v,used);
				newvars:=COMP(v,newvars);
			END;
		END;
		RETURN FORMKQUANT(op,FORMKLVAR(INV(newvars)),
			repvar(psi,old,new,used,denied,bbsubstvar));
	ELSIF op=TVAR THEN
		WHILE old<>SIL DO
			ADV(old,p,old);
			ADV(new,t,new);
			IF EQUAL(phi,p)=1 THEN RETURN t; END;
		END;
		RETURN phi;
	ELSE
		(* apply all substitution to the bb-formula phi *)
		result:=phi;
		WHILE old<>SIL DO
			ADV(old,p,old);
			ADV(new,t,new);
			result:=bbsubstvar(result,p,t);
		END;
		RETURN result;
	END;
END repvar;

PROCEDURE GENVAR(var,xdenied:LIST): LIST;
(* generate variable. var is a variable; xdenied is a list of variables (all
symbols in this list must been exploded!).  The returned variable has a name
which is disjoint to the names of the variables in the list xdenied. (refere
the procedure GENSYM from the module MASSYM2.) *)
	VAR name, sort, xname, xsort, sname,(* x for explode, s for symbol *)
		num, q, new: LIST;
BEGIN
	FORPVAR(var,name,sort);
	xname:=FORVTGET(name);
	xsort:=FORVTGET(sort);
	(* check whether var is in denied or not *)
	IF MEMBER(LIST2(xname,xsort),xdenied)=0 THEN RETURN var; END;
	num:=0;
	(* generate new varaibles until no name conflicts occurs *)
	REPEAT
		new:=SIL;      (* FORMAT von XDENIED hat sich geaendert!!!! *)
		num:=num+1;
		q:=num;
		REPEAT
			new:=COMP(MASREM(q,10),new);
			q:=q DIV 10;
		UNTIL q = 0;
		new:=COMP(MASORD("N"),new);
		new:=CCONC(xname,new);
	UNTIL MEMBER(LIST2(new,xsort),xdenied)=0;
	sname:=FORVTENTER(new);
	RETURN FORMKVAR(sname,sort)
END GENVAR;


(******************************************************************************
*				 S I M P L I F Y			      *
******************************************************************************)

PROCEDURE FORSMPL(phi: LIST; bbsmpl, bbmkneg: PROCF1): LIST;
(* formula simplify. phi is a formula, simplifybb is a bb-procedure to
simplify a bb-formula; bbmkneg is a bb-procedure to negate a bb-formula; a
formula phi1 equivalent to phi is returned. The formula phi1 is simplified,
that means the constants VERUM and FALSUM are eliminated, and nested operators
are eliminated. (In this case the procedure takes advantage of associativity
of ET and VEL, and the idempotenz of NON.) *)
	VAR op, red, arg, arg1, arg2, simparg1, simparg2, newop, newarg: LIST;
	VAR newred, vars, qform, simpqform, elem, result: LIST;
BEGIN
	IF phi = SIL THEN RETURN SIL; END;

	FORPFOR(phi,op,red);
	IF (op=VERUM) OR (op=FALSUM) THEN
		RETURN phi;
	ELSIF op=NON THEN
		FORPUNOPA(red,arg);
		newarg:=FORSMPL(arg,bbsmpl,bbmkneg);
		RETURN formkneg(newarg,bbmkneg);
	ELSIF op=ET THEN
		result:=SIL;
		WHILE red <> SIL DO
			FORPARGS(red,arg,red);
			newarg:=FORSMPL(arg,bbsmpl,bbmkneg);
			IF newarg=FALSUM
			THEN
				RETURN FORMKCNST(FALSUM);
			ELSIF newarg<>VERUM (* VERUM is neutral w.r.t. ET *)
			THEN
			(* Try to simplify the formula with the law of
			* associativity *)
				FORPARGS(newarg,newop,newred);
				IF newop=ET THEN
					WHILE newred <> SIL DO
						FORPARGS(newred,elem,newred);
						result:=COMP(elem,result);
					END;

				ELSE
					result:=COMP(newarg,result);
				END;
			END;
		END;
		IF result<>SIL 	THEN
			RETURN FORMKFOR(ET,INV(result));
		ELSE
			RETURN FORMKCNST(VERUM);
		END
	ELSIF op=VEL THEN
		result:=SIL;
		WHILE red <> SIL DO
			FORPARGS(red,arg,red);
			newarg:=FORSMPL(arg,bbsmpl,bbmkneg);
			IF newarg=VERUM THEN
				RETURN VERUM;
			ELSIF newarg<>FALSUM THEN
			(* Try to simplify the formula with the law of
			* associativity *)
				FORPARGS(newarg,newop,newred);
				IF newop=VEL THEN
					WHILE newred <> SIL DO
						FORPARGS(newred,elem,newred);
						result:=COMP(elem,result);
					END;
				ELSE
					result:=COMP(newarg,result);
				END;
			END;
		END;
		IF result<>SIL 	THEN
			RETURN FORMKFOR(VEL,INV(result));
		ELSE
			RETURN FORMKCNST(FALSUM);
		END;
 	ELSIF (op=IMP) OR (op=REP) THEN
		RETURN smplimpl(phi,bbsmpl,bbmkneg);
 	ELSIF op=EQUIV THEN
		FORPBINOPA(red,arg1,arg2);
		simparg1:=FORSMPL(arg1,bbsmpl,bbmkneg);
		simparg2:=FORSMPL(arg2,bbsmpl,bbmkneg);
		IF simparg1=VERUM THEN
			RETURN simparg2
		ELSIF simparg2=VERUM THEN
			RETURN simparg1
		ELSIF simparg1=FALSUM THEN
			RETURN formkneg(simparg2,bbmkneg);
		ELSIF simparg2=FALSUM THEN
			RETURN formkneg(simparg1,bbmkneg);
		ELSE
			RETURN FORMKBINOP(EQUIV,simparg1,simparg2);
		END;
	ELSIF op=XOR THEN
		FORPBINOPA(red,arg1,arg2);
		simparg1:=FORSMPL(arg1,bbsmpl,bbmkneg);
		simparg2:=FORSMPL(arg2,bbsmpl,bbmkneg);
		IF simparg1=FALSUM THEN
			RETURN simparg2
		ELSIF simparg2=FALSUM THEN
			RETURN simparg1
		ELSIF simparg1=VERUM THEN
			RETURN formkneg(simparg2,bbmkneg);
		ELSIF simparg2=VERUM THEN
			RETURN formkneg(simparg1,bbmkneg);
		ELSE
			RETURN FORMKBINOP(XOR,simparg1,simparg2);
		END;
	ELSIF (op=EXIST) OR (op=FORALL) THEN
		FORPQUANTA(red,vars,qform);
		simpqform:=FORSMPL(qform,bbsmpl,bbmkneg);
		IF (simpqform=VERUM) OR (simpqform=FALSUM) THEN
			RETURN simpqform
		ELSE
			RETURN FORMKQUANT(op,vars,simpqform);
		END;
	ELSIF op=TVAR THEN
		RETURN phi;
	ELSE
		RETURN bbsmpl(phi);
	END;
END FORSMPL;

PROCEDURE smplimpl(phi:LIST;bbsmpl,bbmkneg:PROCF1):LIST;
(* simplify implication. phi is either an implication or a replication; bbsmpl
is bb-procedure to simplify a bb-formula; bbmkneg is a bb-procedure to negate
a bb-formula; a simplification of phi is returned. (see the description of
FORSMPL). *)
	VAR sprem, sconcl,prem,concl,op,newarg,newop,arg1,arg2: LIST;
BEGIN
	FORPBINOP(phi,op,arg1,arg2);
	IF op=IMP THEN
		prem:=arg1;
		concl:=arg2;
	ELSE
		prem:=arg2;
		concl:=arg1;
	END;
	IF prem=FALSUM THEN
		RETURN FORMKCNST(VERUM);
	ELSIF prem=VERUM THEN
		RETURN FORSMPL(concl,bbsmpl,bbmkneg);
	ELSIF concl=FALSUM THEN
		RETURN FORSMPL(FORMKUNOP(NON,prem),bbsmpl,bbmkneg);
	ELSIF concl=VERUM THEN
		RETURN concl;
	ELSE
		sprem:=FORSMPL(prem,bbsmpl,bbmkneg);
		sconcl:=FORSMPL(concl,bbsmpl,bbmkneg);
		IF sprem=FALSUM THEN
			RETURN FORMKCNST(VERUM);
		ELSIF sprem=VERUM THEN
			RETURN sconcl;
		ELSIF sconcl=FALSUM THEN
			FORPFOR(sprem,newop,newarg);
			IF newop=NON THEN
				RETURN newarg;
			ELSE
				RETURN FORMKUNOP(NON,sprem)
			END;
		ELSIF sconcl=VERUM THEN
			RETURN sconcl;
		ELSE
			IF EQUAL(sprem,sconcl)=1 THEN RETURN VERUM; END;
			IF op=IMP THEN
				RETURN FORMKBINOP(IMP,sprem,sconcl);
			ELSE
				RETURN FORMKBINOP(REP,sconcl,sprem);
			END;
		END;
	END;
END smplimpl;


PROCEDURE FORSIMPLIFY(phi: LIST; smart: PROCF1; bbsmpl, bbmkneg: PROCF1):LIST;
(* formula simplify. phi is a formula, smart is a function
to do smart simplification on a list of atomic formulas. 
simplifybb is a bb-procedure to
simplify a bb-formula; bbmkneg is a bb-procedure to negate a bb-formula.
A simplification of phi is returned. *)
	VAR op, red, arg, arg1, arg2, simparg1, simparg2, newop, newarg: LIST;
	VAR newred, vars, qform, simpqform, elem, result: LIST;
	VAR aflist, cflist,psi: LIST;
BEGIN
	IF phi = SIL THEN RETURN SIL; END;

	FORPFOR(phi,op,red);
	IF (op=VERUM) OR (op=FALSUM) THEN
		RETURN phi;
	ELSIF op=NON THEN
		FORPUNOPA(red,arg);
		newarg:=FORSIMPLIFY(arg,smart,bbsmpl,bbmkneg);
		RETURN formkneg(newarg,bbmkneg);
	ELSIF (op=ET) OR (op=VEL) THEN
		result:=SIL;
		WHILE red<>SIL DO
			FORPARGS(red,arg,red);
			arg:=FORSIMPLIFY(arg,smart,bbsmpl,bbmkneg);
			result:=SimplifyComp(arg,op,result);
			IF (result=VERUM) OR (result=FALSUM) THEN
				RETURN result;
			END; 
		END;
		result:=DoSmartSimplify(result,op,smart);
		IF (result=VERUM) OR (result=FALSUM) THEN
			RETURN result;
		END;
		IF (result=VERUM) OR (result=FALSUM) THEN
			RETURN FORMKCNST(result);
		ELSIF result=SIL THEN
			IF op=ET THEN 
				RETURN FORMKCNST(VERUM); 
			ELSE (* IF op=VEL *)
				RETURN FORMKCNST(FALSUM); 
			END;
		ELSIF RED(result)=SIL THEN 	(* only one argument *)
			RETURN FIRST(result)
		ELSE
			RETURN FORMKFOR(op,result);
		END;
 	ELSIF (op=IMP) OR (op=REP) THEN
		RETURN smplimpl(phi,bbsmpl,bbmkneg);
 	ELSIF op=EQUIV THEN
		FORPBINOPA(red,arg1,arg2);
		simparg1:=FORSIMPLIFY(arg1,smart,bbsmpl,bbmkneg);
		simparg2:=FORSIMPLIFY(arg2,smart,bbsmpl,bbmkneg);
		IF simparg1=VERUM THEN
			RETURN simparg2
		ELSIF simparg2=VERUM THEN
			RETURN simparg1
		ELSIF simparg1=FALSUM THEN
			RETURN formkneg(simparg2,bbmkneg);
		ELSIF simparg2=FALSUM THEN
			RETURN formkneg(simparg1,bbmkneg);
		ELSE
			IF EQUAL(simparg1,simparg2)=1 THEN RETURN VERUM; END; 
			RETURN FORMKBINOP(EQUIV,simparg1,simparg2);
		END;
	ELSIF op=XOR THEN
		FORPBINOPA(red,arg1,arg2);
		simparg1:=FORSIMPLIFY(arg1,smart,bbsmpl,bbmkneg);
		simparg2:=FORSIMPLIFY(arg2,smart,bbsmpl,bbmkneg);
		IF simparg1=FALSUM THEN
			RETURN simparg2
		ELSIF simparg2=FALSUM THEN
			RETURN simparg1
		ELSIF simparg1=VERUM THEN
			RETURN formkneg(simparg2,bbmkneg);
		ELSIF simparg2=VERUM THEN
			RETURN formkneg(simparg1,bbmkneg);
		ELSE
			IF EQUAL(simparg1,simparg2)=1 THEN RETURN FALSUM; END; 
			RETURN FORMKBINOP(XOR,simparg1,simparg2);
		END;
	ELSIF (op=EXIST) OR (op=FORALL) THEN
		FORPQUANTA(red,vars,qform);
		simpqform:=FORSIMPLIFY(qform,smart,bbsmpl,bbmkneg);
		IF (simpqform=VERUM) OR (simpqform=FALSUM) THEN
			RETURN simpqform
		ELSE
			RETURN FORMKQUANT(op,vars,simpqform);
		END;
	ELSIF op=TVAR THEN
		RETURN phi;
	ELSE
		RETURN bbsmpl(phi);
	END;
END FORSIMPLIFY;

PROCEDURE SimplifyComp(phi,op,L:LIST):LIST;
(* simplify composition. phi is a formula. 
op is either ET or VEL. L is a list of formulas. 
A list of formulas is returned. If phi is already a element of L then L is 
returned. If the operator symbol of phi is equal to op then all arguments 
of this operator of phi are inserted in L, otherwise phi is inserted in L.
L is modified, the result is returned. If the result of SimplifyComp
is VERUM or FALUSM then VERUM or FALSUM are returned, not the LIST of 
one of these symbols. 
*)
	VAR args,psi: LIST;
BEGIN
	IF ((op=ET) AND (phi=FALSUM) ) OR 
	   ((op=VEL) AND (phi=VERUM) ) 
	THEN
		RETURN phi;
	ELSIF (phi=VERUM) OR (phi=FALSUM) THEN
		RETURN L;
	END; 
	IF FORGOP(phi)=op THEN
		args:=FORGARGS(phi);
		WHILE args<>SIL DO
			ADV(args,psi,args);
			L:=SetAddQ(psi,L);
		END;
		RETURN L;
	ELSE
		RETURN SetAddQ(phi,L);
	END;
END SimplifyComp;

PROCEDURE DoSmartSimplify(L,op:LIST;smart:PROCF1):LIST;
(* do smart simplification. L is a list of formulas. op is a the operator
ET or VEL. smart is a procedure for smart simplification. The
simplified formula op(L) is returned. *)
	VAR aflist, cflist, psi, result,smartresult: LIST;
BEGIN
	aflist:=SIL; 
	result:=SIL;
	WHILE L<>SIL DO
		ADV(L,psi,L);
		IF FORISBBFOR(psi)
		THEN
			aflist:=COMP(psi,aflist);
		ELSE
			result:=COMP(psi,result);
		END;
	END;
	IF aflist<>SIL THEN
		smartresult:=smart(FORMKFOR(op,aflist));
		IF NOT FORISATOM(smartresult) THEN 
			smartresult:=FORMKFOR(FORGOP(smartresult),
				INV(FORGARGS(smartresult)));
		END;
		RETURN SimplifyComp(smartresult,op,result);
	ELSE
		RETURN result;
	END; 
END DoSmartSimplify;

PROCEDURE FORSIMPLIFYP(phi,maxlevel: LIST;
	smart: PROCF1; bbsmpl, bbmkneg: PROCF1):LIST;
(* formula simplify prune. phi is a formula, level, maxlevel are atoms, 
smart is a function to do smart simplification on a list of atomic formulas. 
simplifybb is a bb-procedure to
simplify a bb-formula; bbmkneg is a bb-procedure to negate a bb-formula.
maxlevel defines the number of levels that are simplified, 1 means only 
the top-level, zero means simplify the hole tree.
A simplification of phi is returned. *)
BEGIN
	RETURN simplifyp(phi,1,maxlevel,smart,bbsmpl,bbmkneg);
END FORSIMPLIFYP;

PROCEDURE simplifyp(phi,level,maxlevel: LIST;
	smart: PROCF1; bbsmpl, bbmkneg: PROCF1):LIST;
(* formula simplify prune. phi is a formula, level, maxlevel are atoms, 
smart is a function to do smart simplification on a list of atomic formulas. 
simplifybb is a bb-procedure to
simplify a bb-formula; bbmkneg is a bb-procedure to negate a bb-formula.
maxlevel defines the number of levels that are simplified, 1 means only 
the top-level, zero means simplify the hole tree. level is the current level.
A simplification of phi is returned. *)
	VAR op, red, arg, arg1, arg2, simparg1, simparg2, newop, newarg: LIST;
	VAR newred, vars, qform, simpqform, elem, result: LIST;
	VAR aflist, cflist,psi: LIST;
BEGIN
	IF phi = SIL THEN RETURN SIL; END;
	IF level=maxlevel+1 THEN RETURN phi; END; 

	FORPFOR(phi,op,red);
	IF (op=VERUM) OR (op=FALSUM) THEN
		RETURN phi;
	ELSIF op=NON THEN
		FORPUNOPA(red,arg);
		newarg:=simplifyp(arg,level+1,maxlevel,smart,bbsmpl,bbmkneg);
		RETURN formkneg(newarg,bbmkneg);
	ELSIF (op=ET) OR (op=VEL) THEN
		result:=SIL;
		WHILE red<>SIL DO
			FORPARGS(red,arg,red);
			arg:=simplifyp(arg,level+1,maxlevel,smart,bbsmpl,bbmkneg);
			result:=SimplifyComp(arg,op,result);
			IF (result=VERUM) OR (result=FALSUM) THEN
				RETURN result;
			END; 
		END;
		result:=DoSmartSimplify(result,op,smart);
		IF (result=VERUM) OR (result=FALSUM) THEN
			RETURN result;
		END;
		IF (result=VERUM) OR (result=FALSUM) THEN
			RETURN FORMKCNST(result);
		ELSIF result=SIL THEN
			IF op=ET THEN 
				RETURN FORMKCNST(VERUM); 
			ELSE (* IF op=VEL *)
				RETURN FORMKCNST(FALSUM); 
			END;
		ELSIF RED(result)=SIL THEN 	(* only one argument *)
			RETURN FIRST(result)
		ELSE
			RETURN FORMKFOR(op,result);
		END;
 	ELSIF (op=IMP) OR (op=REP) THEN
		RETURN smplimpl(phi,bbsmpl,bbmkneg);
 	ELSIF op=EQUIV THEN
		FORPBINOPA(red,arg1,arg2);
		simparg1:=simplifyp(arg1,level+1,maxlevel,smart,bbsmpl,bbmkneg);
		simparg2:=simplifyp(arg2,level+1,maxlevel,smart,bbsmpl,bbmkneg);
		IF simparg1=VERUM THEN
			RETURN simparg2
		ELSIF simparg2=VERUM THEN
			RETURN simparg1
		ELSIF simparg1=FALSUM THEN
			RETURN formkneg(simparg2,bbmkneg);
		ELSIF simparg2=FALSUM THEN
			RETURN formkneg(simparg1,bbmkneg);
		ELSE
			IF EQUAL(simparg1,simparg2)=1 THEN RETURN VERUM; END; 
			RETURN FORMKBINOP(EQUIV,simparg1,simparg2);
		END;
	ELSIF op=XOR THEN
		FORPBINOPA(red,arg1,arg2);
		simparg1:=simplifyp(arg1,level+1,maxlevel,smart,bbsmpl,bbmkneg);
		simparg2:=simplifyp(arg2,level+1,maxlevel,smart,bbsmpl,bbmkneg);
		IF simparg1=FALSUM THEN
			RETURN simparg2
		ELSIF simparg2=FALSUM THEN
			RETURN simparg1
		ELSIF simparg1=VERUM THEN
			RETURN formkneg(simparg2,bbmkneg);
		ELSIF simparg2=VERUM THEN
			RETURN formkneg(simparg1,bbmkneg);
		ELSE
			IF EQUAL(simparg1,simparg2)=1 THEN RETURN FALSUM; END; 
			RETURN FORMKBINOP(XOR,simparg1,simparg2);
		END;
	ELSIF (op=EXIST) OR (op=FORALL) THEN
		FORPQUANTA(red,vars,qform);
		simpqform:=simplifyp(qform,level+1,maxlevel,smart,bbsmpl,bbmkneg);
		IF (simpqform=VERUM) OR (simpqform=FALSUM) THEN
			RETURN simpqform
		ELSE
			RETURN FORMKQUANT(op,vars,simpqform);
		END;
	ELSIF op=TVAR THEN
		RETURN phi;
	ELSE
		RETURN bbsmpl(phi);
	END;
END simplifyp;

(******************************************************************************
*	 P R E P A R E   Q U A N T I F I E R   E L I M I N A T I O N	      *
******************************************************************************)

PROCEDURE FORPREPQE(phi: LIST; bbmkneg: PROCF1):LIST;
(* formula prepare quantifier elimination. phi is a prenex formula; bbmkneg is
a bb-procedure to negate a bb-formula; a formula psi equivalent to phi is
returned. psi is built according to the following rules: If the innermost
block of quantifiers is an exist-quantifier, then matrix(phi) is transformed
in CNF and the innermost block of quantifiers is moved inside the conjunction.
If the innermost quantifier is a forall-quantifier, then matrix(phi) is
transformed in DNF and the innermost block of quantifiers is moved inside the
disjunction.*)
	VAR op, quant, red, parg, phi1, lastop, qblocks, vblocks, psi,
		arg, psi1, lvar: LIST;
BEGIN
	IF phi=SIL THEN RETURN SIL; END;

	FORPFOR(phi,op,red);
	IF (op<>EXIST) AND (op<>FORALL) THEN
		RETURN phi;
	END;
	qblocks:=SIL;
	vblocks:=SIL;
	WHILE (op=EXIST) OR (op=FORALL) DO
		FORPQUANTA(red,lvar,phi1);
		qblocks:=COMP(op,qblocks);
		vblocks:=COMP(lvar,vblocks);
		FORPFOR(phi1,op,red);
	END;
	(* now: qblocks is a list of all blocks of quantifiers of phi, but
	the sequence is reveresed. *)
	ADV(qblocks,quant,qblocks);
	ADV(vblocks,lvar,vblocks);
	(* now: quant is the innermost quantifier *)
	IF quant=EXIST THEN
		psi1:=FORMKDNF(phi1,bbmkneg);
	ELSE 		(* op=FORALL *)
		psi1:=FORMKCNF(phi1,bbmkneg);
	END;
	FORPFOR(psi1,op,red);
	psi:=SIL;
	WHILE red<>SIL DO
		FORPARGS(red,arg,red);
		parg:=FORMKQUANT(quant,lvar,arg);	(* simplification? *)
		psi:=COMP(parg,psi);
	END;
	psi:=FORMKFOR(op,psi);
	WHILE qblocks<>SIL DO
		ADV(qblocks,quant,qblocks);
		ADV(vblocks,lvar,vblocks);
		psi:=FORMKQUANT(quant,lvar,psi);
	END;
	RETURN psi;
END FORPREPQE;


(******************************************************************************
*  E L I M I N A T E   E X T E N D E D   O P E R A T I O N   S Y M B O L S    *
******************************************************************************)

PROCEDURE FORELIMXOPS(phi :LIST; pref: LIST): LIST;
(* formula eliminate extended operation symbols. phi is formula, pref is a
symbol of the set \{VEL, ET, NON\}; FORELIMXOPS returns a formula phi1
equivalent to phi. If pref is NON then this function does nothing. Otherwise
this function replaces all subterms of phi with the operators IMP, REP, EQUIV
or XOR with terms with the operators VEL, ET and NON. There are two different
substitutions for EQUIV and XOR. If pref=ET (pref=VEL) then the outermost
operator of the replacement terms for EQUIV, XOR is ET (VEL). *)
	VAR op, arglist, arg, arg1, arg2, prem, concl, lvar, qform: LIST;
	VAR elimarg1, elimarg2, res: LIST;
BEGIN
	IF phi = SIL THEN RETURN SIL; END;
	IF pref = NON THEN RETURN phi; END;

	IF (pref <> VEL) AND (pref <> ET) THEN
		ERROR(severe,"FORMELIMXOPS: wrong preferenz given (assume NON)");
		RETURN phi;
	END;

	FORPFOR(phi,op,arglist);
	IF (op=VERUM) OR (op=FALSUM) THEN
		RETURN phi;
	ELSIF op=NON THEN
		FORPUNOPA(arglist,arg);
		RETURN FORMKUNOP(NON,FORELIMXOPS(arg,pref));
	ELSIF (op=VEL) OR (op=ET) THEN
		res:=SIL;
		WHILE arglist <> SIL DO
			FORPARGS(arglist,arg,arglist);
			res:=COMP(FORELIMXOPS(arg,pref),res);
		END;
		RETURN FORMKFOR(op,INV(res));
	ELSIF (op=EXIST) OR (op=FORALL) THEN
		FORPQUANTA(arglist,lvar,qform);
		RETURN FORMKQUANT(op,lvar,FORELIMXOPS(qform,pref));
	ELSIF op=IMP THEN
		FORPBINOPA(arglist,prem,concl);
		RETURN FORMKBINOP(VEL,FORMKUNOP(NON,FORELIMXOPS(prem,pref)),
			FORELIMXOPS(concl,pref));
	ELSIF op=REP THEN
		FORPBINOPA(arglist,concl,prem);
		RETURN FORMKBINOP(VEL,FORELIMXOPS(concl,pref),
			FORMKUNOP(NON,FORELIMXOPS(prem,pref)));
	ELSIF (op=EQUIV) AND (pref=VEL) THEN
		FORPBINOPA(arglist,arg1,arg2);
		elimarg1:=FORELIMXOPS(arg1,pref);
		elimarg2:=FORELIMXOPS(arg2,pref);
		RETURN FORMKBINOP(VEL,
				FORMKBINOP(ET,elimarg1,elimarg2),
				FORMKBINOP(ET,
					FORMKUNOP(NON,elimarg1),
					FORMKUNOP(NON,elimarg2)));
	ELSIF (op=EQUIV) AND (pref=ET) THEN
		FORPBINOPA(arglist,arg1,arg2);
		elimarg1:=FORELIMXOPS(arg1,pref);
		elimarg2:=FORELIMXOPS(arg2,pref);
		RETURN FORMKBINOP(ET,
			FORMKBINOP(VEL,FORMKUNOP(NON,elimarg1),elimarg2),
			FORMKBINOP(VEL,elimarg1,FORMKUNOP(NON,elimarg2)));
	ELSIF (op=XOR) AND (pref=VEL) THEN
		FORPBINOPA(arglist,arg1,arg2);
		elimarg1:=FORELIMXOPS(arg1,pref);
		elimarg2:=FORELIMXOPS(arg2,pref);
		RETURN FORMKBINOP(VEL,
			FORMKBINOP(ET,FORMKUNOP(NON,elimarg1),elimarg2),
			FORMKBINOP(ET,elimarg1,FORMKUNOP(NON,elimarg2)));
	ELSIF (op=XOR) AND (pref=ET) THEN
		FORPBINOPA(arglist,arg1,arg2);
		elimarg1:=FORELIMXOPS(arg1,pref);
		elimarg2:=FORELIMXOPS(arg2,pref);
		RETURN FORMKBINOP(ET,
			FORMKBINOP(VEL,elimarg1,elimarg2),
			FORMKBINOP(VEL,
				FORMKUNOP(NON,elimarg1),
				FORMKUNOP(NON,elimarg2)));
	ELSE
		RETURN phi;
	END;
END FORELIMXOPS;


(******************************************************************************
*                              F O R R E P A F S                              *
******************************************************************************)

PROCEDURE FORREPAFS(phi,rep:LIST):LIST;
(* formula replace atomic formulas. phi is a formula. rep is a 
assoc list of the form (old1,new1,old2,new2,...), where old1,... and
new1,.. are atomic formulas. Each occurence of oldi in phi is 
replaced with newi. *)
	VAR op,arg1,arg2,args,argi,found,result: LIST;
	VAR quantifier, bvars: LIST;
BEGIN
	op:=FORGOP(phi);
	IF (op=NON) THEN 
		RETURN FORMKUNOP(NON,FORREPAFS(FIRST(FORGARGS(phi)),rep));
	ELSIF (op=ET) OR (op=VEL) THEN
		args:=FORGARGS(phi);
		result:=SIL;
		WHILE args<>SIL DO 
			ADV(args,argi,args);
			result:=COMP(FORREPAFS(argi,rep),result);
		END;
		RETURN FORMKFOR(op,INV(result));
	ELSIF (op=EXIST) OR (op=FORALL) THEN
		FORPQUANT(phi,quantifier,bvars,arg1);
		RETURN FORMKQUANT(quantifier,bvars,FORREPAFS(arg1,rep));
	ELSIF (op=IMP) OR (op=REP) OR (op=EQUIV) OR (op=XOR) THEN
		FORPBINOP(phi,op,arg1,arg2);
		RETURN FORMKBINOP(op,FORREPAFS(arg1,rep),FORREPAFS(arg2,rep));
	ELSE (* phi is a atomic formula *)
		found:=ASSOCQ(phi,rep);
		IF found=SIL THEN 
			RETURN phi;
		ELSE
			RETURN FIRST(found);
		END;
	END;
END FORREPAFS;

(******************************************************************************
*			  A P P L Y   T O   A T O M			      *
******************************************************************************)

PROCEDURE FORAPPLYAT(phi:LIST; dosomething:PROCF1): LIST;
(* formula apply to atomic formular. phi is a formula; a formular in which all
atomic formulas psi are substituted with dosomething(psi) is returned.  *)
	VAR op, red, arg, arg1, arg2, lvar, psi, name, sort, result: LIST;
BEGIN
	IF phi=SIL THEN RETURN SIL; END;

	FORPFOR(phi,op,red);
	IF (op=VERUM) OR (op=FALSUM) THEN
  		RETURN dosomething(phi)
   	ELSIF op=NON THEN
		FORPUNOPA(red,arg);
		RETURN FORMKUNOP(NON,FORAPPLYAT(arg,dosomething));
   	ELSIF (op=VEL) OR (op=ET) THEN
		result:=SIL;
		WHILE red<>SIL DO
			FORPARGS(red,arg,red);
			result:=COMP(FORAPPLYAT(arg,dosomething),result);
   		END;
		RETURN FORMKFOR(op,INV(result));
	ELSIF (op=IMP) OR (op=REP) OR (op=EQUIV) OR (op=XOR) THEN
		FORPBINOPA(red,arg1,arg2);
		RETURN FORMKBINOP(op,FORAPPLYAT(arg1,dosomething),
			FORAPPLYAT(arg2,dosomething))
	ELSIF (op=EXIST) OR (op=FORALL) THEN
		FORPQUANTA(red,lvar,psi);
		RETURN FORMKQUANT(op,lvar,FORAPPLYAT(psi,dosomething));
	ELSIF op=TVAR THEN
		RETURN dosomething(phi);
	ELSE
		RETURN dosomething(phi);
	END;
END FORAPPLYAT;

PROCEDURE FORAPPLYATF2(phi,param1:LIST; dosomething:PROCF2): LIST;
(* formula apply to atomic formula f2. 
phi is a formula; param1 is an arbitrary list object,
a formula in which all atomic formulas psi are substituted with 
dosomething(psi,param1) is returned.  *)
	VAR op, red, arg, arg1, arg2, lvar, psi, name, sort, result: LIST;
BEGIN
	IF phi=SIL THEN RETURN SIL; END;
	FORPFOR(phi,op,red);
	IF (op=VERUM) OR (op=FALSUM) THEN
  		RETURN dosomething(phi,param1)
   	ELSIF op=NON THEN
		FORPUNOPA(red,arg);
		RETURN FORMKUNOP(NON,FORAPPLYATF2(arg,param1,dosomething));
   	ELSIF (op=VEL) OR (op=ET) THEN
		result:=SIL;
		WHILE red<>SIL DO
			FORPARGS(red,arg,red);
			result:=COMP(FORAPPLYATF2(arg,param1,dosomething),
				result);
   		END;
		RETURN FORMKFOR(op,INV(result));
	ELSIF (op=IMP) OR (op=REP) OR (op=EQUIV) OR (op=XOR) THEN
		FORPBINOPA(red,arg1,arg2);
		RETURN FORMKBINOP(op,FORAPPLYATF2(arg1,param1,dosomething),
			FORAPPLYATF2(arg2,param1,dosomething))
	ELSIF (op=EXIST) OR (op=FORALL) THEN
		FORPQUANTA(red,lvar,psi);
		RETURN FORMKQUANT(op,lvar,
			FORAPPLYATF2(psi,param1,dosomething));
	ELSIF op=TVAR THEN
		RETURN dosomething(phi,param1);
	ELSE
		RETURN dosomething(phi,param1);
	END;
END FORAPPLYATF2;

(******************************************************************************
*                  C O U N T   A T O M I C   F O R M U L A S                  *
******************************************************************************)

PROCEDURE FORCOUNTAF(phi:LIST): LIST;
(* formula count atomic formulas. phi is a formula; 
The number of the atomic formulas in the formula phi is returned. *)
	VAR op, red, arg, arg1, arg2, lvar, psi, number: LIST;
BEGIN
	IF phi=SIL THEN RETURN SIL; END;

	FORPFOR(phi,op,red);
	IF (op=VERUM) OR (op=FALSUM) THEN
  		RETURN 1;
   	ELSIF op=NON THEN
		FORPUNOPA(red,arg);
		RETURN FORCOUNTAF(arg);
   	ELSIF (op=VEL) OR (op=ET) THEN
		number:=0;
		WHILE red<>SIL DO
			FORPARGS(red,arg,red);
			number:=number+FORCOUNTAF(arg);
   		END;
		RETURN number;
	ELSIF (op=IMP) OR (op=REP) OR (op=EQUIV) OR (op=XOR) THEN
		FORPBINOPA(red,arg1,arg2);
		RETURN FORCOUNTAF(arg1)+FORCOUNTAF(arg2)
	ELSIF (op=EXIST) OR (op=FORALL) THEN
		FORPQUANTA(red,lvar,psi);
		RETURN FORCOUNTAF(psi);
	ELSIF op=TVAR THEN
		RETURN 1;
	ELSE
		RETURN 1;
	END;
END FORCOUNTAF;


(******************************************************************************
*	      C O N T A I N S   B O U N D E D   V A R I A B L E		      *
******************************************************************************)

PROCEDURE FORCONTBDVAR(phi:LIST; svar: LIST): BOOLEAN;
(* formula contain bound variable. phi is a formula; svar is a variable;
FORCONTBDVAR returns true, if and only if phi contains svar as a bound
variable. *)
	VAR op, red, arg, arg1, arg2, lvar, psi, varlist, var: LIST;
BEGIN
	IF phi=SIL THEN RETURN FALSE; END;

	FORPFOR(phi,op,red);
	IF (op=VERUM) OR (op=FALSUM) THEN
  		RETURN FALSE;
   	ELSIF op=NON THEN
		FORPUNOPA(phi,arg);
		RETURN FORCONTBDVAR(arg,svar);
   	ELSIF (op=VEL) OR (op=ET) THEN
		WHILE red<>SIL  DO
			FORPARGS(red,arg,red);
			IF FORCONTBDVAR(arg,svar) THEN RETURN TRUE; END;
   		END;
		RETURN FALSE; 
	ELSIF (op=IMP) OR (op=REP) OR (op=EQUIV) OR (op=XOR) THEN
		FORPBINOPA(red,arg1,arg2);
		RETURN FORCONTBDVAR(arg1,svar) OR FORCONTBDVAR(arg2,svar)
	ELSIF (op=EXIST) OR (op=FORALL) THEN
		FORPQUANTA(red,lvar,psi);
		FORPLVAR(lvar,varlist);
		WHILE varlist<>SIL DO
			FORPARGS(varlist,var,varlist);
			IF  EQUAL(svar,var)=1 THEN RETURN TRUE; END; 
		END;
		RETURN FORCONTBDVAR(psi,svar);
	ELSIF op=TVAR THEN
		RETURN FALSE;
	ELSE
		RETURN FALSE;
	END;
END FORCONTBDVAR;


(******************************************************************************
*		      C O N T A I N S   V A R I A B L E			      *
******************************************************************************)

PROCEDURE FORCONTVAR(phi:LIST; svar: LIST; bbcontvar: PROCFB2): BOOLEAN;
(* formula contain variable. phi is a formula; var is a variable; bbcontvar is
a procedure, which tests whether a bb-formula contains a variable or not;
FORCONTVAR returns true, if and only if phi contains var as a free variable.
*)
	VAR op, red, arg, arg1, arg2, lvar, psi, varlist, var: LIST;
BEGIN
	IF phi=SIL THEN RETURN FALSE; END;

	FORPFOR(phi,op,red);
	IF (op=VERUM) OR (op=FALSUM) THEN
  		RETURN FALSE;
   	ELSIF op=NON THEN
		FORPUNOPA(phi,arg);
		RETURN FORCONTVAR(arg,svar,bbcontvar);
   	ELSIF (op=VEL) OR (op=ET) THEN
		WHILE red<>SIL DO
			FORPARGS(red,arg,red);
			IF FORCONTVAR(arg,svar,bbcontvar) THEN RETURN TRUE END;
   		END;
		RETURN FALSE;
	ELSIF (op=IMP) OR (op=REP) OR (op=EQUIV) OR (op=XOR) THEN
		FORPBINOPA(red,arg1,arg2);
		RETURN FORCONTVAR(arg1,svar,bbcontvar) OR
			FORCONTVAR(arg2,svar,bbcontvar)
	ELSIF (op=EXIST) OR (op=FORALL)	THEN
		FORPQUANTA(red,lvar,psi);
		FORPLVAR(lvar,varlist);
		WHILE varlist<>SIL  DO
			FORPARGS(varlist,var,varlist);
			IF EQUAL(svar,var)=1 THEN RETURN FALSE; END; 
		END;
		RETURN FORCONTVAR(psi,svar,bbcontvar);
	ELSIF op=TVAR THEN
		RETURN EQUAL(svar,var)=1;
	ELSE
		RETURN bbcontvar(phi,var);
	END;
END FORCONTVAR;


(******************************************************************************
*	    G E N E R A L   A U X I L I A R Y   P R O C E D U R E S           *
******************************************************************************)

PROCEDURE notsymbol(sym :LIST): LIST;
(* not symbol. sym is a symbol of the set {VERUM, FALSUM, VEL, ET, IMP, REP,
EQUIV, XOR, FORALL, EXIST}; returns the (defined) negation of this symbol. *)
BEGIN
	IF sym=VERUM	THEN RETURN FALSUM;	END;
	IF sym=FALSUM	THEN RETURN VERUM;	END;
	IF sym=VEL	THEN RETURN ET;		END;
	IF sym=ET	THEN RETURN VEL;	END;
	IF sym=EXIST	THEN RETURN FORALL;	END;
	IF sym=FORALL	THEN RETURN EXIST;	END;
	IF sym=IMP	THEN RETURN REP;	END;
	IF sym=REP	THEN RETURN IMP;	END;
	IF sym=EQUIV	THEN RETURN XOR;	END;
	IF sym=XOR	THEN RETURN EQUIV;	END;
END notsymbol;


PROCEDURE formkneg(phi:LIST; bbmkneg: PROCF1): LIST;
(* formula make negation. phi is a formula, bbmkneg a procedure to negate a
bb-formula, a simplification of a negation of phi is returned. *)
	VAR op, arg, left, right: LIST;
BEGIN
	FORPFOR(phi,op,arg);
	IF op=VERUM THEN
		RETURN FORMKCNST(FALSUM)
	ELSIF op=FALSUM THEN
		RETURN FORMKCNST(VERUM)
	ELSIF op=NON THEN
		RETURN arg;
	ELSIF (op=VEL) OR (op=ET) OR (op=IMP) OR (op=REP) OR
		(op=TVAR) OR (op=EXIST) OR (op=FORALL) THEN
		RETURN FORMKUNOP(NON,phi);
	ELSIF op=EQUIV THEN
		FORPBINOPA(arg,left,right);
		RETURN FORMKBINOP(XOR,left,right);
	ELSIF op=XOR THEN
		FORPBINOPA(arg,left,right);
		RETURN FORMKBINOP(EQUIV,left,right);
	ELSIF op=TVAR THEN 
		RETURN FORMKUNOP(NON,phi);
	ELSE
		RETURN bbmkneg(phi);
	END;
END formkneg;


(******************************************************************************
*				   M A I N				      *
******************************************************************************)

(* BEGIN *) (* OF INITIALIZATION *)

END MASLOG.

(* -EOF- *)