/** * This program (working title: MAS Prover) is an automated tableaux prover * for epistemic logic (S5n). * Copyright (C) 2007 Elske van der Vaart and Gert van Valkenhoef * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package nl.rug.ai.mas.oops; import java.util.*; import nl.rug.ai.mas.oops.formula.*; import nl.rug.ai.mas.oops.model.ConfigurableModel; import nl.rug.ai.mas.oops.model.ConfigurableModel.Relation; import nl.rug.ai.mas.oops.model.KripkeModel; import nl.rug.ai.mas.oops.parser.Context; import nl.rug.ai.mas.oops.parser.FormulaParser; import nl.rug.ai.mas.oops.tableau.*; import nl.rug.ai.mas.oops.tableau.ModalRuleFactory.RuleID; /** * Proves formulas using a tableau. */ public class Prover { /** * Tableau mode (whether to PROVE a formula, or to do SAT checking). */ private enum Mode { PROVE, SAT }; /** * The axiom system this prover was constructed from. */ private final AxiomSystem d_axiomSystem; /** * The Tableau instance. */ private final Tableau d_tableau; /** * The parser instance. */ private final FormulaParser d_formulaAdapter; /** * The (parser) context. */ private final Context d_context; /** * The model relations */ private final Vector<Relation> d_relations; /** * Constructor. * Constructs a new prover object. May be used to parse, prove or sat-check * any number of formulas. */ public Prover(AxiomSystem as) { RuleID[] ruleIdsArray = as.rules; Vector<RuleID> rules = new Vector<RuleID>(); Collections.addAll(rules, ruleIdsArray); Relation[] relationsArray = as.relations; Vector<Relation> relations = new Vector<Relation>(); Collections.addAll(relations, relationsArray); Context c = new Context(); Vector<Rule> rules1 = PropositionalRuleFactory.build(c); rules1.addAll(ModalRuleFactory.build(c, rules)); d_formulaAdapter = new FormulaParser(c); d_tableau = new Tableau(rules1); d_context = c; d_axiomSystem = as; d_relations = relations; } /** * Provability checker (uses ~formula not satisfiable, then formula * provable). * @return true if formula is provable. */ public boolean provable(Formula formula) throws TableauErrorException { forceValid(formula); Tableau.BranchState result = d_tableau.tableau( new Negation(formula)); if (result == Tableau.BranchState.ERROR) { throw new TableauErrorException(d_tableau.getError()); } return result == Tableau.BranchState.CLOSED; } /** * @return true if formula is satisfiable. */ public boolean satisfiable(Formula formula) throws TableauErrorException { forceValid(formula); Tableau.BranchState result = d_tableau.tableau(formula); if (result == Tableau.BranchState.ERROR) { throw new TableauErrorException(d_tableau.getError()); } return result == Tableau.BranchState.OPEN; } public AxiomSystem getAxiomSystem() { return d_axiomSystem; } /** * Retrieve the used Tableau instance. */ public Tableau getTableau() { return d_tableau; } public boolean validate(Formula f) { return d_axiomSystem.validator.validate(f); } private void forceValid(Formula f) throws TableauErrorException { if (!validate(f)) { throw new TableauErrorException("Formula invalid in the system " + d_axiomSystem); } else if (!f.isConcrete()) { throw new TableauErrorException("Formula " + f + " is not concrete."); } } /** * @return true if formula is provable. */ public boolean provable(String formula) throws TableauErrorException { return provable(parse(formula)); } /** * @return true if formula is satisfiable. */ public boolean satisfiable(String formula) throws TableauErrorException { return satisfiable(parse(formula)); } /** * Parse a string into a Formula object. Note that calling this method * separately is useful, e.g. when using a Tableau Observer that expects a * list of syntactic entities in advance. * * @see nl.rug.ai.mas.oops.model.ModelConstructingObserver */ public Formula parse(String formula) throws TableauErrorException { if (!d_formulaAdapter.parse(formula)) { throw new TableauErrorException("Could not parse formula"); } return d_formulaAdapter.getFormula(); } /** * @return the parser context. */ public Context getContext() { return d_context; } public KripkeModel getModel() { return new ConfigurableModel(d_context.getAgentIdView(), d_relations); } public static void main(String [] args) { String formula = null; Mode mode = Mode.PROVE; AxiomSystem system = AxiomSystem.S5; int argNum = 0; // Parse command-line while (argNum < args.length) { String arg = args[argNum++]; if (arg.equals("--sat")) { mode = Mode.SAT; } else if (arg.equals("--prover")) { try { system = AxiomSystem.valueOf(args[argNum++]); } catch (Exception e) { System.out.println("Invalid prover specified"); return; } } else if (formula == null && !arg.startsWith("--") && !arg.startsWith("-") ) { formula = arg; } } if (formula == null) { System.out.println("Please supply a formula on the command line."); return; } Prover p = system.buildProver(); try { if (mode == Mode.PROVE) { System.out.println(p.provable(formula)); } else { System.out.println(p.satisfiable(formula)); } } catch (TableauErrorException e) { System.out.println(e); System.exit(1); } } }