// mm.java Copyright (c) 2003 Norman Megill nm at alum dot mit dot edu // Copyright under terms of GNU General Public License // To compile on Windows: Download and install the 1.3.1 SDK. The setup // file that I downloaded from java.sun.com on 14-Jun-2002 was called // j2sdk-1_3_1_03-win.exe and its size was 44526848 bytes. After // installing, open the Command Prompt, cd to the directory with mm.java, // and type // C:\jdk1.3.1_03\bin\javac mm.java // Warning: If compiled with j2sdk1.4.0, the program will not run under // the native Microsoft JVM in Internet Explorer. // History: 5-Aug-1997 Initial release // 13-Apr-2001 Upgraded to Java 2 by Marcello DeMarinis // 5-Jun-2002 Fixed "Save As Axiom" bug that incorrectly suppressed // user-created theorems from the list of choices when // the proof of the theorem contained hypotheses // 7-Aug-2003 Fixed typos in Euclid's axioms eu8 and eu3 // (found by Russell O'Connor) // Note: I have included the entire program in one file (contrary to // recommended Java programming guidelines) as I believe this is more // convenient for distribution. Also, the main class mm is not upper-case // (contrary to recommended Java programming guidelines) because I got tired // of shifting; thus this file must be called mm.java, not MM.java nor Mm.java. // A future version may or may not include sound effects. This program was // originally written when such things were new and trendy. Do you think they // should be kept, or are they too silly? Anyway, if you strip out all lines // with the tag "/* [sound] */", you will only need the standalone // file "mm.java" to recompile the program and will not need any .au files. /* [sound] */ // The .au files used are: /* [sound] */ // /* [sound] */ // bart.aye_carumba.au /* [sound] */ // beep_spring.au /* [sound] */ // boing.au /* [sound] */ // bomb.au /* [sound] */ // bubble1.au /* [sound] */ // clink.au /* [sound] */ // drip.au /* [sound] */ // gate.au /* [sound] */ // hypspc.au /* [sound] */ // ni.au /* [sound] */ // ouch.au /* [sound] */ // splat.au /* [sound] */ // whoosh.au /* [sound] */ // wzzz.au /* [sound] */ // wzzz2.au /* [sound] */ // zoom.au import java.applet.*; import java.awt.*; import java.util.*; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; import java.awt.event.ItemListener; import java.awt.event.ItemEvent; public class mm extends Applet implements ActionListener, ItemListener { //private Button clear_button; private Choice option_choices; static boolean proofInfoModeFlag = false; private Button proof_exit_button; static boolean axiomInfoModeFlag = false; static boolean selectLogicModeFlag = false; static int infoModeAxiomToShow; private Button info_exit_button; private Choice axiom_choices; private Label axiom_label = new Label("Axioms:", Label.RIGHT); private Vector axiomChoiceVec; static final int MAX_AXIOM_CHOICE_LEN = 30; // So axiom choice menu // won't be too long private TextArea proof_text; // Current state of stack static State currentState; // Undo/redo variables static Stack undoStack; static Stack redoStack; // (Future - not implemented yet - NDM) static final int UNDO_STACK_KEEP = 100; // Undo depth // A future version should parse this from a file? // Connective storage static Connective[] connectiveArr; static String connectiveLabels; // For speedup static String connectiveLabelMap; // For speedup // Axiom storage static final int PROP_CALC = 0; static final int PROP_DEFS = 1; static final int PRED_CALC = 2; static final int PRED_DEFS = 3; static final int SET_THEORY = 4; static final int SET_DEFS = 5; static final int IMPL_LOGIC = 6; static final int INTUIT_LOGIC = 7; static final int MODAL_LOGIC = 8; static final int GODEL_LOGIC = 9; static final int QUANTUM_LOGIC = 10; static final int EUCLID = 11; static final int WEAKD_LOGIC = 12; static final String[] familyName = { "Propositional Calculus", "Propositional Calculus + Definitions", "Predicate Calculus", "Predicate Calculus + Definitions", "ZFC Set Theory", "ZFC Set Theory + Definitions", "Implicational Logic", "Intuitionist Propositional Calculus", "Modal Logic", "Modal Provability Logic", "Quantum Logic", "Euclidean Geometry", "Weak D-Complete Logic" }; static final int FAMILIES = 13; static final Vector[] axiomFamily = new Vector[FAMILIES]; // Vectors of State static int currentFamily; // Current family static Axiom[] axiomArr; // Current axiom set static Vector userTheorems; // Vector of State private CheckboxGroup cg = new CheckboxGroup(); private Checkbox[] logic_select = new Checkbox[FAMILIES]; static int maxAxiomHypotheses; // set by axiom with the most hypotheses static final Color DARK_GREEN = new Color(0, 100, 0); static final Color BACKGROUND_COLOR = new Color(210, 255, 255); static final Color PROOF_BACKGROUND_COLOR = new Color(255, 255, 165); static final Color INFO_BACKGROUND_COLOR = new Color(255, 210, 255); // Font parameters static final int FONT_SIZE = 12; static final String MATH_FONT_NAME = "Courier"; //"TimesRoman"; // math variables & ASCII symbols static final Font MATH_PLAIN_FONT = new Font(MATH_FONT_NAME, Font.PLAIN, FONT_SIZE); static final Font MATH_ITALIC_FONT = new Font(MATH_FONT_NAME, Font.ITALIC, FONT_SIZE); static final int Y_INCREMENT = (FONT_SIZE * 3) / 2; // Line-to-line spacing static final int X_INIT = FONT_SIZE / 2; // Left margin static final int CHAR_SPACE = -1; // Space between chars of token static final int WHITE_SPACE = 2; // Space between tokens static int currentX; static int currentY; /* [sound] */ // Sound effects /* [sound] */ static public String audioName = null; /* [sound] */ static public boolean enableAudioFlag = false; /* [sound] */ static private Vector audioSaveNameVec = new Vector(); /* [sound] */ static private Vector audioSaveClipVec = new Vector(); // If run as an application instead of applet, runningMain will be true static boolean runningMain = false; public static void main(String argv[]) { System.out.println("Running main"); runningMain = true; mm mainmm = new mm(); mainmm.init(); int i; for (i = 0; i < axiomArr.length; i++) { VariableName.init(); System.out.println(PrimFormula.getDisplay(axiomArr[i].assertion, false)); } } // main public void init() { Connective tmpConnective; Vector connectiveVec; Axiom tmpAxiom; Vector axiomVec; userTheorems = new Vector(); currentFamily = PROP_CALC; currentState = new State(); undoStack = new Stack(); redoStack = new Stack(); connectiveVec = new Vector(); // A future version could parse this from a file? // ****** Connectives ******** // Arguments are label, type of result, # vars, display notation template // Labels are same as in Metamath set.mm // Implication tmpConnective = new Connective("wi", "wff", 2, "( $1 -> $2 )"); tmpConnective.setArgtype(0, "wff"); tmpConnective.setArgtype(1, "wff"); connectiveVec.addElement(tmpConnective); // Negation tmpConnective = new Connective("wn", "wff", 1, "-. $1"); tmpConnective.setArgtype(0, "wff"); connectiveVec.addElement(tmpConnective); // Universal quantifier tmpConnective = new Connective("wal", "wff", 2, "A. $1 $2"); tmpConnective.setArgtype(0, "var"); tmpConnective.setArgtype(1, "wff"); connectiveVec.addElement(tmpConnective); // Define equality as primitive on classes, not variables for convenience tmpConnective = new Connective("weq", "wff", 2, "$1 = $2"); tmpConnective.setArgtype(0, "class"); tmpConnective.setArgtype(1, "class"); connectiveVec.addElement(tmpConnective); // Define membership as primitive on classes, not variable for convenience tmpConnective = new Connective("wel", "wff", 2, "$1 e. $2"); tmpConnective.setArgtype(0, "class"); tmpConnective.setArgtype(1, "class"); connectiveVec.addElement(tmpConnective); // Convert variable to class (invisible notation) tmpConnective = new Connective("cv", "class", 1, "$1"); tmpConnective.setArgtype(0, "var"); connectiveVec.addElement(tmpConnective); // Biconditional tmpConnective = new Connective("wb", "wff", 2, "( $1 <-> $2 )"); tmpConnective.setArgtype(0, "wff"); tmpConnective.setArgtype(1, "wff"); connectiveVec.addElement(tmpConnective); // Disjunction ('or') tmpConnective = new Connective("wo", "wff", 2, "( $1 \\/ $2 )"); tmpConnective.setArgtype(0, "wff"); tmpConnective.setArgtype(1, "wff"); connectiveVec.addElement(tmpConnective); // Conjunction ('and') tmpConnective = new Connective("wa", "wff", 2, "( $1 /\\ $2 )"); tmpConnective.setArgtype(0, "wff"); tmpConnective.setArgtype(1, "wff"); connectiveVec.addElement(tmpConnective); // Existential quantifier tmpConnective = new Connective("wex", "wff", 2, "E. $1 $2"); tmpConnective.setArgtype(0, "var"); tmpConnective.setArgtype(1, "wff"); connectiveVec.addElement(tmpConnective); // Proper substitution of $1 for $2 tmpConnective = new Connective("wsb", "wff", 3, "[ $1 / $2 ] $3"); tmpConnective.setArgtype(0, "var"); tmpConnective.setArgtype(1, "var"); tmpConnective.setArgtype(2, "wff"); connectiveVec.addElement(tmpConnective); // Abstraction class notation ('the class of sets x such that // P is true'). A class is not necessarily a set (i.e. may not exist) tmpConnective = new Connective("cab", "class", 2, "{ $1 | $2 }"); tmpConnective.setArgtype(0, "var"); tmpConnective.setArgtype(1, "wff"); connectiveVec.addElement(tmpConnective); // Subclass tmpConnective = new Connective("wss", "wff", 2, "$1 (_ $2"); tmpConnective.setArgtype(0, "class"); tmpConnective.setArgtype(1, "class"); connectiveVec.addElement(tmpConnective); // Empty set tmpConnective = new Connective("cnul", "class", 0, "(/)"); connectiveVec.addElement(tmpConnective); // Union of two classes tmpConnective = new Connective("cun", "class", 2, "( $1 u. $2 )"); tmpConnective.setArgtype(0, "class"); tmpConnective.setArgtype(1, "class"); connectiveVec.addElement(tmpConnective); // Intersection of two classes tmpConnective = new Connective("cin", "class", 2, "( $1 i^i $2 )"); tmpConnective.setArgtype(0, "class"); tmpConnective.setArgtype(1, "class"); connectiveVec.addElement(tmpConnective); // Union of a class tmpConnective = new Connective("cuni", "class", 1, "U. $1"); tmpConnective.setArgtype(0, "class"); connectiveVec.addElement(tmpConnective); // Intersection of a class tmpConnective = new Connective("cint", "class", 1, "|^| $1"); tmpConnective.setArgtype(0, "class"); connectiveVec.addElement(tmpConnective); // Modal logic connectives // Necessity (box) tmpConnective = new Connective("wnec", "wff", 1, "[] $1"); tmpConnective.setArgtype(0, "wff"); connectiveVec.addElement(tmpConnective); // Possibility (diamond) tmpConnective = new Connective("wposs", "wff", 1, "<> $1"); tmpConnective.setArgtype(0, "wff"); connectiveVec.addElement(tmpConnective); // False constant tmpConnective = new Connective("wfalse", "wff", 0, "_|_"); connectiveVec.addElement(tmpConnective); // Betweenness predicate (Euclidean geometry) tmpConnective = new Connective("wbt", "wff", 3, "B $1 $2 $3"); tmpConnective.setArgtype(0, "var"); tmpConnective.setArgtype(1, "var"); tmpConnective.setArgtype(2, "var"); connectiveVec.addElement(tmpConnective); // Distance predicate (Euclidean geometry) tmpConnective = new Connective("wd", "wff", 4, "D $1 $2 $3 $4"); tmpConnective.setArgtype(0, "var"); tmpConnective.setArgtype(1, "var"); tmpConnective.setArgtype(2, "var"); tmpConnective.setArgtype(3, "var"); connectiveVec.addElement(tmpConnective); // Convert vector to array connectiveArr = new Connective[connectiveVec.size()]; connectiveVec.copyInto(connectiveArr); // Build connective label and map strings for faster lookup connectiveLabels = new String(" "); connectiveLabelMap = new String(""); for (int i = 0; i < connectiveArr.length; i++) { connectiveLabels = connectiveLabels + connectiveArr[i].label + " "; // Only the valueOf will be used; the other characters are placeholders connectiveLabelMap = connectiveLabelMap + String.valueOf((char)i) + connectiveArr[i].label; } // ********************** Axioms ***************************** // All axioms are specified in RPN; $n is variable placeholder // Labels are same as in Metamath set.mm // ************ Propositional calculus axiomVec = new Vector(); // ax-1 $a |- ( P -> ( Q -> P ) ) $. // We define a new variable (ax_1Axiom) for the axiom if // we will use it again in another system later. Otherwise // we just use the variable tmpAxiom. Axiom ax_1Axiom = new Axiom("ax-1", "wi $1 wi $2 $1", "Axiom of simplification (propositional calculus)"); axiomVec.addElement(ax_1Axiom); // ax-2 $a |- ( ( P -> ( Q -> R ) ) -> ( ( P -> Q ) -> // ( P -> R ) ) ) $. Axiom ax_2Axiom = new Axiom("ax-2", "wi wi $1 wi $2 $3 wi wi $1 $2 wi $1 $3", "Axiom of distribution (propositional calculus)"); axiomVec.addElement(ax_2Axiom); // ax-3 $a |- ( ( -. P -> -. Q ) -> ( Q -> P ) ) $. tmpAxiom = new Axiom("ax-3", "wi wi wn $1 wn $2 wi $2 $1", "Axiom of contraposition (propositional calculus)"); axiomVec.addElement(tmpAxiom); // maj $e |- ( P -> Q ) $. // min $e |- P $. // ax-mp $a |- Q $. Axiom rule_mpAxiom = new Axiom("ax-mp", "$2", "Inference rule of modus ponens (propositional calculus)"); rule_mpAxiom.addHyp("$1"); rule_mpAxiom.addHyp("wi $1 $2"); axiomVec.addElement(rule_mpAxiom); axiomFamily[PROP_CALC] = axiomVec; // ************ Propositional calculus with definitions axiomVec = (Vector)(axiomFamily[PROP_CALC].clone()); // Start w/ prop calc // df-bi1 $a |- ( ( P <-> Q ) -> ( P -> Q ) ) $. Axiom df_bi1Axiom = new Axiom("df-bi1", "wi wb $1 $2 wi $1 $2", "Definition of biconditional (part 1 of 3)"); axiomVec.addElement(df_bi1Axiom); // df-bi2 $a |- ( ( P <-> Q ) -> ( Q -> P ) ) $. Axiom df_bi2Axiom = new Axiom("df-bi2", "wi wb $1 $2 wi $2 $1", "Definition of biconditional (part 2 of 3)"); axiomVec.addElement(df_bi2Axiom); // df-bi3 $a |- ( ( P -> Q ) -> ( ( Q -> P ) -> ( P <-> Q ) ) ) $. Axiom df_bi3Axiom = new Axiom("df-bi3", "wi wi $1 $2 wi wi $2 $1 wb $1 $2", "Definition of biconditional (part 3 of 3)"); axiomVec.addElement(df_bi3Axiom); // df-or $a |- ( ( P \/ Q ) <-> ( -. P -> Q ) ) $. Axiom df_orAxiom = new Axiom("df-or", "wb wo $1 $2 wi wn $1 $2", "Definition of disjunction (logical OR)"); axiomVec.addElement(df_orAxiom); // df-an $a |- ( ( P /\ Q ) <-> -. ( P -> -. Q ) ) $. Axiom df_anAxiom = new Axiom("df-an", "wb wa $1 $2 wn wi $1 wn $2", "Definition of conjunction (logical AND)"); axiomVec.addElement(df_anAxiom); axiomFamily[PROP_DEFS] = axiomVec; // ************ Predicate calculus axiomVec = (Vector)(axiomFamily[PROP_CALC].clone()); // Start w/ prop calc // ax-4 $a |- ( A. x P -> P ) $. tmpAxiom = new Axiom("ax-4", "wi wal $1 $2 $2", "Axiom of specification (predicate calculus)"); axiomVec.addElement(tmpAxiom); // ax-5 $a |- ( A. x ( A. x P -> Q ) -> ( A. x P -> A. x Q ) ) $. tmpAxiom = new Axiom("ax-5", "wi wal $1 wi wal $1 $2 $3 wi wal $1 $2 wal $1 $3", "Axiom of quantified implication (predicate calculus)"); axiomVec.addElement(tmpAxiom); // ax-6 $a |- ( -. A. x -. A. x P -> P ) $. tmpAxiom = new Axiom("ax-6", "wi wn $1 wal $2 wn wal $2 $1", "Axiom of quantified negation (predicate calculus)"); axiomVec.addElement(tmpAxiom); // ax-7 $a |- ( A. x A. y P -> A. y A. x P ) $. tmpAxiom = new Axiom("ax-7", "wi wal $1 wal $2 $3 wal $2 wal $1 $3", "Axiom of quantifier commutation (predicate calculus)"); axiomVec.addElement(tmpAxiom); // ax-g.1 $e |- P $. // ax-gen $a |- A. x P $. tmpAxiom = new Axiom("ax-gen", "wal $2 $1", "Inference rule of generalization (predicate calculus)"); tmpAxiom.addHyp("$1"); axiomVec.addElement(tmpAxiom); // ax-8 $a |- ( x = y -> ( x = z -> y = z ) ) $. tmpAxiom = new Axiom("ax-8", "wi weq cv $1 cv $2 wi weq cv $1 cv $3 weq cv $2 cv $3", "Axiom of equality (predicate calculus)"); axiomVec.addElement(tmpAxiom); // ax-9 $a |- ( A. x ( x = y -> A. x P ) -> P ) $. tmpAxiom = new Axiom("ax-9", "wi wal $1 wi weq cv $1 cv $2 wal $1 $3 $3", "Axiom of existence (predicate calculus)"); axiomVec.addElement(tmpAxiom); // ax-10 $a |- ( A. x x = y -> ( A. x P -> A. y P ) ) $. tmpAxiom = new Axiom("ax-10", "wi wal $1 weq cv $1 cv $2 wi wal $1 $3 wal $2 $3", "Axiom of quantifier substitution (predicate calculus)"); axiomVec.addElement(tmpAxiom); // ax-11 $a |- ( -. A. x x = y -> // ( x = y -> ( P -> A. x ( x = y -> P ) ) ) ) $. tmpAxiom = new Axiom("ax-11", "wi wn wal $1 weq cv $1 cv $2 wi weq cv $1 cv $2 wi" + " $3 wal $1 wi weq cv $1 cv $2 $3", "Axiom of variable substitution (predicate calculus)"); axiomVec.addElement(tmpAxiom); // ax-12 $a |- ( -. A. z z = x -> ( -. A. z z = y -> // ( x = y -> A. z x = y ) ) ) $. tmpAxiom = new Axiom("ax-12", "wi wn wal $1 weq cv $1 cv $2 wi wn wal $1 weq cv $1 cv $3 wi" + " weq cv $2 cv $3 wal $1 weq cv $2 cv $3", "Axiom of quantifier introduction (predicate calculus)"); axiomVec.addElement(tmpAxiom); // ax-13 $a |- ( x = y -> ( x e. z -> y e. z ) ) $. tmpAxiom = new Axiom("ax-13", "wi weq cv $1 cv $2 wi wel cv $1 cv $3 wel cv $2 cv $3", "Axiom of equality (predicate calculus)"); axiomVec.addElement(tmpAxiom); // ax-14 $a |- ( x = y -> ( z e. x -> z e. y ) ) $. tmpAxiom = new Axiom("ax-14", "wi weq cv $1 cv $2 wi wel cv $3 cv $1 wel cv $3 cv $2", "Axiom of equality (predicate calculus)"); axiomVec.addElement(tmpAxiom); // ax-15 and ax-16 are called ax-16 and ax-17 in set.mm and Metamath book // ax-16 $a |- ( A. x x = y -> ( P -> A. x P ) ) $. tmpAxiom = new Axiom("ax-15", "wi wal $1 weq cv $1 cv $2 wi $3 wal $1 $3", "Axiom of distinct variables (predicate calculus)"); tmpAxiom.addDistinct("$1 $2"); axiomVec.addElement(tmpAxiom); // ax-17 $a |- ( P -> A. x P ) $. tmpAxiom = new Axiom("ax-16", "wi $1 wal $2 $1", "Axiom of quantifier introduction (predicate calculus)"); tmpAxiom.addDistinct("$1 $2"); axiomVec.addElement(tmpAxiom); axiomFamily[PRED_CALC] = axiomVec; // ************ Predicate calculus with definitions axiomVec = (Vector)(axiomFamily[PRED_CALC].clone()); // Start w/ pred calc axiomVec.addElement(df_bi1Axiom); axiomVec.addElement(df_bi2Axiom); axiomVec.addElement(df_bi3Axiom); axiomVec.addElement(df_orAxiom); axiomVec.addElement(df_anAxiom); // df-ex $a |- ( E. x P <-> -. A. x -. P ) $. Axiom df_exAxiom = new Axiom("df-ex", "wb wex $1 $2 wn wal $1 wn $2", "Definition of existential quantifier"); axiomVec.addElement(df_exAxiom); // df-sub $a |- [ x / y ] P <-> // ( ( y = x -> P ) /\ E. y ( y = x /\ P ) ) ) $. Axiom df_subAxiom = new Axiom("df-sub", "wb wsb $1 $2 $3 wa wi weq cv $2 cv $1 $3 wex $2 wa weq cv $2 cv $1 $3", "Definition of proper substitution of x for y in P(y) to result in P(x)"); axiomVec.addElement(df_subAxiom); axiomFamily[PRED_DEFS] = axiomVec; // ************ Set theory axiomVec = (Vector)(axiomFamily[PRED_CALC].clone()); // Start w/ pred calc axiomVec.addElement(df_bi1Axiom); axiomVec.addElement(df_bi2Axiom); axiomVec.addElement(df_bi3Axiom); axiomVec.addElement(df_orAxiom); axiomVec.addElement(df_anAxiom); axiomVec.addElement(df_exAxiom); // ax-ext $a |- ( A. x ( x e. y <-> x e. z ) -> y = z ) $. tmpAxiom = new Axiom("ax-ext", "wi wal $1 wb wel cv $1 cv $2 wel cv $1 cv $3 weq cv $2 cv $3", "Axiom of extensionality (set theory)"); tmpAxiom.addDistinct("$1 $2"); tmpAxiom.addDistinct("$1 $3"); axiomVec.addElement(tmpAxiom); // ax-rep $a |- E. x ( E. y A. z ( P -> z = y ) -> // A. z ( z e. x <-> E. x ( x e. y /\ P ) ) ) $. tmpAxiom = new Axiom("ax-rep", "wex $1 wi wex $2 wal $3 wi $4 weq cv $3 cv $2 wal $3 wb wel cv $3 cv $1" + " wex $1 wa wel cv $1 cv $2 $4", "Axiom of replacement (set theory)"); tmpAxiom.addDistinct("$1 $2"); tmpAxiom.addDistinct("$1 $3"); tmpAxiom.addDistinct("$2 $3"); tmpAxiom.addDistinct("$2 $4"); axiomVec.addElement(tmpAxiom); // ax-un $a |- E. x A. y ( E. x ( y e. x /\ x e. z ) -> y e. x ) $. tmpAxiom = new Axiom("ax-un", "wex $1 wal $2 wi wex $1 wa wel cv $2 cv $1 wel cv $1 cv $3 wel cv $2 cv $1" , "Axiom of union (set theory)"); tmpAxiom.addDistinct("$1 $2"); tmpAxiom.addDistinct("$1 $3"); tmpAxiom.addDistinct("$2 $3"); axiomVec.addElement(tmpAxiom); // ax-pow $a |- E. x A. y ( A. x ( x e. y -> x e. z ) -> y e. x ) $. tmpAxiom = new Axiom("ax-pow", "wex $1 wal $2 wi wal $1 wi wel cv $1 cv $2 wel cv $1 cv $3 wel cv $2 cv $1" , "Axiom of power set (set theory)"); tmpAxiom.addDistinct("$1 $2"); tmpAxiom.addDistinct("$1 $3"); tmpAxiom.addDistinct("$2 $3"); axiomVec.addElement(tmpAxiom); // ax-reg $a |- ( x e. y -> // E. x ( x e. y /\ A. z ( z e. x -> -. z e. y ) ) ) $. tmpAxiom = new Axiom("ax-reg", "wi wel cv $1 cv $2 wex $1 wa wel cv $1 cv $2 wal $3 wi wel cv $3 cv $1 wn" + " wel cv $3 cv $2" , "Axiom of regularity (set theory)"); tmpAxiom.addDistinct("$1 $2"); tmpAxiom.addDistinct("$1 $3"); tmpAxiom.addDistinct("$2 $3"); axiomVec.addElement(tmpAxiom); // ax-inf $a |- E. x ( y e. x /\ // A. y ( y e. x -> E. z ( y e. z /\ z e. x ) ) ) $. tmpAxiom = new Axiom("ax-inf", "wex $1 wa wel cv $2 cv $1 wal $2 wi wel cv $2 cv $1 wex $3 wa wel cv $2 cv $3" + " wel cv $3 cv $1" , "Axiom of infinity (set theory)"); tmpAxiom.addDistinct("$1 $2"); tmpAxiom.addDistinct("$1 $3"); tmpAxiom.addDistinct("$2 $3"); axiomVec.addElement(tmpAxiom); // ax-ac $a |- E. x A. y A. z ( ( y e. z /\ z e. w ) -> E. w A. y ( E. w // ( ( y e. z /\ z e. w ) /\ ( y e. w /\ w e. x ) ) <-> y = w ) ) $. tmpAxiom = new Axiom("ax-ac", "wex $1 wal $2 wal $3 wi wa wel cv $2 cv $3 wel cv $3 cv $4 wex $4 wal $2" + " wb wex $4 wa wa wel cv $2 cv $3 wel cv $3 cv $4 wa wel cv $2 cv $4 wel" + " cv $4 cv $1 weq cv $2 cv $4" , "Axiom of choice (set theory)"); tmpAxiom.addDistinct("$1 $2"); tmpAxiom.addDistinct("$1 $3"); tmpAxiom.addDistinct("$1 $4"); tmpAxiom.addDistinct("$2 $3"); tmpAxiom.addDistinct("$2 $4"); tmpAxiom.addDistinct("$3 $4"); axiomVec.addElement(tmpAxiom); axiomFamily[SET_THEORY] = axiomVec; // ************ Some set theory definitions axiomVec = (Vector)(axiomFamily[SET_THEORY].clone()); axiomVec.addElement(df_subAxiom); // df-clab $a |- ( y e. { x | P } <-> [ y / x ] P ) $. tmpAxiom = new Axiom("df-ab", "wb wel cv $2 cab $1 $3 wsb $2 $1 $3", "Definition of class abstraction (set theory)"); axiomVec.addElement(tmpAxiom); // df-cleq $p |- ( A = B <-> A. x ( x e. A <-> x e. B ) ) $. tmpAxiom = new Axiom("df-ceq", "wb weq $1 $2 wal $3 wb wel cv $3 $1 wel cv $3 $2", "Definition of class equality (set theory)"); tmpAxiom.addDistinct("$1 $3"); tmpAxiom.addDistinct("$2 $3"); axiomVec.addElement(tmpAxiom); // df-clel $a |- ( A e. B <-> E. x ( x = A /\ x e. B ) ) $. tmpAxiom = new Axiom("df-cel", "wb wel $1 $2 wex $3 wa weq cv $3 $1 wel cv $3 $2", "Definition of class membership (set theory)"); tmpAxiom.addDistinct("$1 $3"); tmpAxiom.addDistinct("$2 $3"); axiomVec.addElement(tmpAxiom); // df-ss $a |- ( A (_ B <-> A. x ( x e. A -> x e. B ) ) $. tmpAxiom = new Axiom("df-ss", "wb wss $1 $2 wal $3 wi wel cv $3 $1 wel cv $3 $2" , "Definition of subclass (set theory)"); tmpAxiom.addDistinct("$1 $3"); tmpAxiom.addDistinct("$2 $3"); axiomVec.addElement(tmpAxiom); // df-un $p |- ( A u. B ) = { x | ( x e. A \/ x e. B ) } $. tmpAxiom = new Axiom("df-un", "weq cun $1 $2 cab $3 wo wel cv $3 $1 wel cv $3 $2", "Definition of union of two classes (set theory)"); tmpAxiom.addDistinct("$1 $3"); tmpAxiom.addDistinct("$2 $3"); axiomVec.addElement(tmpAxiom); // df-in $p |- ( A i^i B ) = { x | ( x e. A /\ x e. B ) } $. tmpAxiom = new Axiom("df-in", "weq cin $1 $2 cab $3 wa wel cv $3 $1 wel cv $3 $2", "Definition of intersection of two classes (set theory)"); tmpAxiom.addDistinct("$1 $3"); tmpAxiom.addDistinct("$2 $3"); axiomVec.addElement(tmpAxiom); // df-nul $p |- (/) = { x | -. x = x } $. tmpAxiom = new Axiom("df-nul", "weq cnul cab $1 wn weq cv $1 cv $1", "Definition of empty set (set theory)"); axiomVec.addElement(tmpAxiom); // df-uni $a |- U. A = { x | E. y ( x e. y /\ y e. A ) } $. tmpAxiom = new Axiom("df-uni", "weq cuni $1 cab $2 wex $3 wa wel cv $2 cv $3 wel cv $3 $1", "Definition of union of a class (set theory)"); tmpAxiom.addDistinct("$1 $2"); tmpAxiom.addDistinct("$1 $3"); axiomVec.addElement(tmpAxiom); // df-int $a |- |^| A = { x | A. y ( y e. A -> x e. y ) } $. tmpAxiom = new Axiom("df-int", "weq cint $1 cab $2 wal $3 wi wel cv $3 $1 wel cv $2 cv $3", "Definition of intersection of a class (set theory)"); tmpAxiom.addDistinct("$1 $2"); tmpAxiom.addDistinct("$1 $3"); axiomVec.addElement(tmpAxiom); axiomFamily[SET_DEFS] = axiomVec; // ************ Implicational logic axiomVec = new Vector(); // (P -> P) Axiom ax_IAxiom = new Axiom("I", "wi $1 $1", "Principal type-scheme for combinator I"); axiomVec.addElement(ax_IAxiom); // ((P -> Q) -> ((R -> P) -> (R -> Q))) tmpAxiom = new Axiom("B", "wi wi $1 $2 wi wi $3 $1 wi $3 $2", "Principal type-scheme for combinator B"); axiomVec.addElement(tmpAxiom); // ((P -> Q) -> ((Q -> R) -> (P -> R))) tmpAxiom = new Axiom("B\'", "wi wi $1 $2 wi wi $2 $3 wi $1 $3", "Principal type-scheme for combinator B\'"); axiomVec.addElement(tmpAxiom); // ((P -> (Q -> R)) -> (Q -> (P -> R))) tmpAxiom = new Axiom("C", "wi wi $1 wi $2 $3 wi $2 wi $1 $3", "Principal type-scheme for combinator C"); axiomVec.addElement(tmpAxiom); // ax-1 $a |- ( P -> ( Q -> P ) ) $. tmpAxiom = new Axiom("K", "wi $1 wi $2 $1", "Principal type-scheme for combinator K"); axiomVec.addElement(tmpAxiom); // ((P -> (P -> Q)) -> (P -> Q)) tmpAxiom = new Axiom("W", "wi wi $1 wi $1 $2 wi $1 $2", "Principal type-scheme for combinator W"); axiomVec.addElement(tmpAxiom); // ax-2 $a |- ( ( P -> ( Q -> R ) ) -> ( ( P -> Q ) -> // ( P -> R ) ) ) $. tmpAxiom = new Axiom("S", "wi wi $1 wi $2 $3 wi wi $1 $2 wi $1 $3", "Principal type-scheme for combinator S"); axiomVec.addElement(tmpAxiom); // (((P -> Q) -> P) -> P) tmpAxiom = new Axiom("Peirce", "wi wi wi $1 $2 $1 $1", "Peirce's law"); axiomVec.addElement(tmpAxiom); // _|_ -> P tmpAxiom = new Axiom("ax-f", "wi wfalse $1", "Axiom for false constant"); axiomVec.addElement(tmpAxiom); // maj $e |- ( P -> Q ) $. // min $e |- P $. // ax-mp $a |- Q $. Axiom rule_DAxiom = new Axiom("D", "$2", "Condensed detachment (modus ponens)"); rule_DAxiom.addHyp("$1"); rule_DAxiom.addHyp("wi $1 $2"); axiomVec.addElement(rule_DAxiom); // (I took out defs for implicational logic; I don't know if df-bi1 - df-bi3 are // acceptable... - NDM) // axiomVec.addElement(df_bi1Axiom); // axiomVec.addElement(df_bi2Axiom); // axiomVec.addElement(df_bi3Axiom); // // // -. P <-> ( P -> _|_ ) // tmpAxiom = new Axiom("df-not", "wb wn $1 wi $1 wfalse", // "Definition of negation (logical NOT)"); // axiomVec.addElement(tmpAxiom); // // axiomVec.addElement(df_orAxiom); // axiomVec.addElement(df_anAxiom); axiomFamily[IMPL_LOGIC] = axiomVec; // ************ Intuitionistic propositional calculus // Source: T. Thatcher Robinson, JSL Vol. 33 No. 2 265-270 (1968) axiomVec = new Vector(); axiomVec.addElement(ax_1Axiom); axiomVec.addElement(ax_2Axiom); // P -> (P \/ Q) tmpAxiom = new Axiom("ax-I3", "wi $1 wo $1 $2", "Axiom 3 for intuitionist propositional calculus"); axiomVec.addElement(tmpAxiom); // Q -> (P \/ Q) tmpAxiom = new Axiom("ax-I4", "wi $2 wo $1 $2", "Axiom 4 for intuitionist propositional calculus"); axiomVec.addElement(tmpAxiom); // ((P -> R) -> ((Q -> R) -> ((P \/ Q) -> R))) tmpAxiom = new Axiom("ax-I5", "wi wi $1 $3 wi wi $2 $3 wi wo $1 $2 $3", "Axiom 5 for intuitionist propositional calculus"); axiomVec.addElement(tmpAxiom); // (P /\ Q) -> P tmpAxiom = new Axiom("ax-I6", "wi wa $1 $2 $1", "Axiom 6 for intuitionist propositional calculus"); axiomVec.addElement(tmpAxiom); // (P /\ Q) -> Q tmpAxiom = new Axiom("ax-I7", "wi wa $1 $2 $2", "Axiom 7 for intuitionist propositional calculus"); axiomVec.addElement(tmpAxiom); // P -> (Q -> (P /\ Q)) tmpAxiom = new Axiom("ax-I8", "wi $1 wi $2 wa $1 $2", "Axiom 8 for intuitionist propositional calculus"); axiomVec.addElement(tmpAxiom); // (P -> ~Q) -> (Q -> ~P) tmpAxiom = new Axiom("ax-I9", "wi wi $1 wn $2 wi $2 wn $1", "Axiom 9 for intuitionist propositional calculus"); axiomVec.addElement(tmpAxiom); // ~P -> (P -> Q) tmpAxiom = new Axiom("ax-I10", "wi wn $1 wi $1 $2", "Axiom 10 for intuitionist propositional calculus"); axiomVec.addElement(tmpAxiom); axiomVec.addElement(rule_mpAxiom); axiomFamily[INTUIT_LOGIC] = axiomVec; // ************ Modal logic // Source: K. Goedel axiomVec = (Vector)(axiomFamily[PROP_CALC].clone()); // []P -> P tmpAxiom = new Axiom("ax-m1", "wi wnec $1 $1", "Axiom 1 for modal logic system M"); axiomVec.addElement(tmpAxiom); // [](P -> Q) -> ([]P -> []Q) tmpAxiom = new Axiom("ax-m2", "wi wnec wi $1 $2 wi wnec $1 wnec $2", "Axiom 2 for modal logic system M"); axiomVec.addElement(tmpAxiom); // []P -> [][]P tmpAxiom = new Axiom("ax-S4", "wi wnec $1 wnec wnec $1", "Axiom extending modal logic to system S4"); axiomVec.addElement(tmpAxiom); // $e |- P $. // $a |- [] P $. Axiom rule_necAxiom = new Axiom("ax-nec", "wnec $1", "Rule of necessitation (modal logic)"); rule_necAxiom.addHyp("$1"); axiomVec.addElement(rule_necAxiom); axiomVec.addElement(df_bi1Axiom); axiomVec.addElement(df_bi2Axiom); axiomVec.addElement(df_bi3Axiom); // <> P <-> -. [] -. P Axiom df_possAxiom = new Axiom("df-poss", "wb wposs $1 wn wnec wn $1", "Definition of possibility"); axiomVec.addElement(df_possAxiom); // <>P -> []<>P tmpAxiom = new Axiom("ax-S5", "wi wposs $1 wnec wposs $1", "Axiom extending modal logic to system S5"); axiomVec.addElement(tmpAxiom); // []P -> <>P tmpAxiom = new Axiom("ax-m1\'", "wi wnec $1 wposs $1", "Weaker alternate axiom 1 for modal logic"); axiomVec.addElement(tmpAxiom); // _|_ <-> -. ( P -> P ) Axiom df_falseAxiom = new Axiom("df-false", "wb wfalse wn wi $1 $1", "Definition of logical false constant"); axiomVec.addElement(df_falseAxiom); axiomVec.addElement(df_orAxiom); axiomVec.addElement(df_anAxiom); axiomFamily[MODAL_LOGIC] = axiomVec; // ************ Modal provability logic // Source: G. Boolos & R. Jeffrey, "Computability and Logic", 1989, ch. 27 axiomVec = (Vector)(axiomFamily[PROP_CALC].clone()); // [](P -> Q) -> ([]P -> []Q) tmpAxiom = new Axiom("ax-g1", "wi wnec wi $1 $2 wi wnec $1 wnec $2", "Axiom 1 for modal provability logic system G"); axiomVec.addElement(tmpAxiom); // []P -> [][]P tmpAxiom = new Axiom("ax-g2", "wi wnec $1 wnec wnec $1", "Axiom 2 for modal provability logic system G"); axiomVec.addElement(tmpAxiom); // []([]P -> P) -> []P tmpAxiom = new Axiom("ax-g3", "wi wnec wi wnec $1 $1 wnec $1", "Axiom 3 for modal provability logic system G"); axiomVec.addElement(tmpAxiom); axiomVec.addElement(rule_necAxiom); axiomVec.addElement(df_bi1Axiom); axiomVec.addElement(df_bi2Axiom); axiomVec.addElement(df_bi3Axiom); axiomVec.addElement(df_possAxiom); axiomVec.addElement(df_falseAxiom); axiomVec.addElement(df_orAxiom); axiomVec.addElement(df_anAxiom); axiomFamily[GODEL_LOGIC] = axiomVec; // ************ Quantum logic // Source: M. Pavicic, Int. J. of Theoretical Physics 32, 1993, p. 1490. axiomVec = new Vector(); // A1. |- A <-> - - A tmpAxiom = new Axiom("A1", "wb $1 wn wn $1", "Axiom A1 for unified quantum logic AUQL"); axiomVec.addElement(tmpAxiom); // A2. |- A \/ B <-> B \/ A tmpAxiom = new Axiom("A2", "wb wo $1 $2 wo $2 $1", "Axiom A2 for unified quantum logic AUQL"); axiomVec.addElement(tmpAxiom); // A3. |- ( A \/ B) \/ C <-> A \/ ( B \/ C ) tmpAxiom = new Axiom("A3", "wb wo wo $1 $2 $3 wo $1 wo $2 $3", "Axiom A3 for unified quantum logic AUQL"); axiomVec.addElement(tmpAxiom); // A4. |- A \/ ( B \/ - B ) <-> B \/ - B tmpAxiom = new Axiom("A4", "wb wo $1 wo $2 wn $2 wo $2 wn $2", "Axiom A4 for unified quantum logic AUQL"); axiomVec.addElement(tmpAxiom); // A5. |- A \/ - ( - A \/ - B ) <-> A tmpAxiom = new Axiom("A5", "wb wo $1 wn wo wn $1 wn $2 $1", "Axiom A5 for unified quantum logic AUQL"); axiomVec.addElement(tmpAxiom); // A6. |- ( A <-> B ) <-> - ( - - A \/ - - B ) \/ - ( - A \/ - B ) tmpAxiom = new Axiom("A6", "wb wb $1 $2 wo wn wo wn wn $1 wn wn $2 wn wo wn $1 wn $2", "Axiom A6 for unified quantum logic AUQL"); axiomVec.addElement(tmpAxiom); // R1. |- A <-> B <=> |- B <-> A tmpAxiom = new Axiom("R1", "wb $2 $1", "Rule R1 for unified quantum logic AUQL"); tmpAxiom.addHyp("wb $1 $2"); axiomVec.addElement(tmpAxiom); // R2. |- A <-> B & |- B <-> C => |- A <-> C tmpAxiom = new Axiom("R2", "wb $1 $3", "Rule R2 for unified quantum logic AUQL"); tmpAxiom.addHyp("wb $2 $3"); tmpAxiom.addHyp("wb $1 $2"); axiomVec.addElement(tmpAxiom); // R3. |- ( C \/ - C ) <-> ( A <-> B ) => |- A <-> B tmpAxiom = new Axiom("R3", "wb $1 $2", "Rule R3 for unified quantum logic AUQL"); tmpAxiom.addHyp("wb wo $3 wn $3 wb $1 $2"); axiomVec.addElement(tmpAxiom); // R4. |- A <-> B => |- - A <-> - B tmpAxiom = new Axiom("R4", "wb wn $1 wn $2", "Rule R4 for unified quantum logic AUQL"); tmpAxiom.addHyp("wb $1 $2"); axiomVec.addElement(tmpAxiom); // R5. |- A <-> B => |- A \/ C <-> B \/ C tmpAxiom = new Axiom("R5", "wb wo $1 $3 wo $2 $3", "Rule R5 for unified quantum logic AUQL"); tmpAxiom.addHyp("wb $1 $2"); axiomVec.addElement(tmpAxiom); // D1. |- ( A /\ B ) <-> - ( - A \/ - B ) tmpAxiom = new Axiom("D1", "wb wa $1 $2 wn wo wn $1 wn $2", "Definition of conjunction for unified quantum logic AUQL"); axiomVec.addElement(tmpAxiom); /* // A1. |- A -> A tmpAxiom = new Axiom("q-A1", "wi $1 $1", "Axiom A1 for quantum logic"); axiomVec.addElement(tmpAxiom); // A2a. |- A -> ~~A tmpAxiom = new Axiom("q-A2a", "wi $1 wn wn $1", "Axiom A2a for quantum logic"); axiomVec.addElement(tmpAxiom); // A2b. |- ~~A -> A tmpAxiom = new Axiom("q-A2b", "wi wn wn $1 $1", "Axiom A2a for quantum logic"); axiomVec.addElement(tmpAxiom); // A3. |- A -> (A \/ B) tmpAxiom = new Axiom("q-A3", "wi $1 wo $1 $2", "Axiom A3 for quantum logic"); axiomVec.addElement(tmpAxiom); // A4. |- B -> (A \/ B) tmpAxiom = new Axiom("q-A4", "wi $2 wo $1 $2", "Axiom A4 for quantum logic"); axiomVec.addElement(tmpAxiom); // A5. |- B -> (A \/ ~A) tmpAxiom = new Axiom("q-A5", "wi $2 wo $1 wn $1", "Axiom A5 for quantum logic"); axiomVec.addElement(tmpAxiom); // R1. From |- A -> B and |- B -> C, infer |- A -> C tmpAxiom = new Axiom("q-R1", "wi $1 $3", "Rule R1 for quantum logic"); tmpAxiom.addHyp("wi $1 $2"); tmpAxiom.addHyp("wi $2 $3"); axiomVec.addElement(tmpAxiom); // R2. From |- A -> B, infer |- ~ B -> ~ A tmpAxiom = new Axiom("q-R2", "wi wn $2 wn $1", "Rule R2 for quantum logic"); tmpAxiom.addHyp("wi $1 $2"); axiomVec.addElement(tmpAxiom); // R3. From |- A -> C and |- B -> C, infer |- (A \/ B) -> C tmpAxiom = new Axiom("q-R3", "wi wo $1 $2 $3", "Rule R3 for quantum logic"); tmpAxiom.addHyp("wi $1 $3"); tmpAxiom.addHyp("wi $2 $3"); axiomVec.addElement(tmpAxiom); // R4a. From |- (B \/ ~ B) -> A, infer |- A tmpAxiom = new Axiom("q-R4a", "$1", "Rule R4a for quantum logic"); tmpAxiom.addHyp("wi wo $2 wn $2 $1"); axiomVec.addElement(tmpAxiom); // R4b. From |- A, infer |- (B \/ ~ B) -> A tmpAxiom = new Axiom("q-R4b", "wi wo $2 wn $2 $1", "Rule R4b for quantum logic"); tmpAxiom.addHyp("$1"); axiomVec.addElement(tmpAxiom); // R5. From |- A -> B and |- B -> A, infer |- (C -> A) -> (C -> B) tmpAxiom = new Axiom("q-R5", "wi wi $3 $1 wi $3 $2", "Rule R5 for quantum logic"); tmpAxiom.addHyp("wi $1 $2"); tmpAxiom.addHyp("wi $2 $1"); axiomVec.addElement(tmpAxiom); // R6. From |- A -> B and |- B -> A, infer |- (A -> C) -> (B -> C) tmpAxiom = new Axiom("q-R6", "wi wi $1 $3 wi $2 $3", "Rule R6 for quantum logic"); tmpAxiom.addHyp("wi $1 $2"); tmpAxiom.addHyp("wi $2 $1"); axiomVec.addElement(tmpAxiom); */ axiomFamily[QUANTUM_LOGIC] = axiomVec; // ************ Euclidean geometry // Source: Alfred Tarski, "What is Elementary Geometry?", in _The Axiomatic // Method_ (ed. Leon Henkin, et. al.), North-Holland, 1959, pp. 16-29 // Axioms are also discussed in: // http://www.math.ucla.edu/~asl/bsl/0502/0502-002.ps axiomVec = (Vector)(axiomFamily[PRED_DEFS].clone()); // Start w/ pred calc // Remove equality axioms for membership connective axiomVec.removeElementAt(axiomFamily[PRED_CALC].size() - 3); axiomVec.removeElementAt(axiomFamily[PRED_CALC].size() - 4); // Note that the 'cv' connective is unnecessary for geometry (since there // are no classes) but we will keep it with the equality connective to // allow us to reuse the axioms of predicate calculus from set theory // without modification. // ax-eq1 $a |- ( x = w -> ( Bxyz -> Bwyz ) ) $. tmpAxiom = new Axiom("eueq1", "wi weq cv $1 cv $4 wi wbt $1 $2 $3 wbt $4 $2 $3", "Axiom of equality for betweenness predicate (Euclidean geometry)"); axiomVec.addElement(tmpAxiom); // ax-eq2 $a |- ( y = w -> ( Bxyz -> Bxwz ) ) $. tmpAxiom = new Axiom("eueq2", "wi weq cv $2 cv $4 wi wbt $1 $2 $3 wbt $1 $4 $3", "Axiom of equality for betweenness predicate (Euclidean geometry)"); axiomVec.addElement(tmpAxiom); // ax-eq3 $a |- ( z = w -> ( Bxyz -> Bxyw ) ) $. tmpAxiom = new Axiom("eueq3", "wi weq cv $3 cv $4 wi wbt $1 $2 $3 wbt $1 $2 $4", "Axiom of equality for betweenness predicate (Euclidean geometry)"); axiomVec.addElement(tmpAxiom); // ax-eq4 $a |- ( x = v -> ( Dxyzw -> Dvyzw ) ) $. tmpAxiom = new Axiom("eueq4", "wi weq cv $1 cv $5 wi wd $1 $2 $3 $4 wd $5 $2 $3 $4", "Axiom of equality for distance predicate (Euclidean geometry)"); axiomVec.addElement(tmpAxiom); // ax-eq5 $a |- ( y = v -> ( Dxyzw -> Dxvzw ) ) $. tmpAxiom = new Axiom("eueq5", "wi weq cv $2 cv $5 wi wd $1 $2 $3 $4 wd $1 $5 $3 $4", "Axiom of equality for distance predicate (Euclidean geometry)"); axiomVec.addElement(tmpAxiom); // ax-eq6 $a |- ( z = v -> ( Dxyzw -> Dxyvw ) ) $. tmpAxiom = new Axiom("eueq6", "wi weq cv $3 cv $5 wi wd $1 $2 $3 $4 wd $1 $2 $5 $4", "Axiom of equality for distance predicate (Euclidean geometry)"); axiomVec.addElement(tmpAxiom); // ax-eq7 $a |- ( w = v -> ( Dxyzw -> Dxyzv ) ) $. tmpAxiom = new Axiom("eueq7", "wi weq cv $4 cv $5 wi wd $1 $2 $3 $4 wd $1 $2 $3 $5", "Axiom of equality for distance predicate (Euclidean geometry)"); axiomVec.addElement(tmpAxiom); // Bxyx -> x=y tmpAxiom = new Axiom("eu1", "wi wbt $1 $2 $1 weq cv $1 cv $2", "Identity axiom for betweenness (Euclidean geometry)"); axiomVec.addElement(tmpAxiom); // Bxyu /\ Byzu -> Bxyz tmpAxiom = new Axiom("eu2", "wi wa wbt $1 $2 $4 wbt $2 $3 $4 wbt $1 $2 $3", "Transitivity axiom for betweenness (Euclidean geometry)"); axiomVec.addElement(tmpAxiom); // (Bxyz /\ Bxyu) /\ -. x=y -> Bxzu \/ Bxuz tmpAxiom = new Axiom("eu3", "wi wa wa wbt $1 $2 $3 wbt $1 $2 $4 wn weq cv $1 cv $2" + " wo wbt $1 $3 $4 wbt $1 $4 $3", "Connectivity axiom for betweenness (Euclidean geometry)"); axiomVec.addElement(tmpAxiom); // Dxyyx tmpAxiom = new Axiom("eu4", "wd $1 $2 $2 $1", "Reflexivity axiom for equidistance (Euclidean geometry)"); axiomVec.addElement(tmpAxiom); // Dxyzz -> x=y tmpAxiom = new Axiom("eu5", "wi wd $1 $2 $3 $3 weq cv $1 cv $2", "Identity axiom for equidistance (Euclidean geometry)"); axiomVec.addElement(tmpAxiom); // Dxyzu /\ Dxyvw -> Dzuvw tmpAxiom = new Axiom("eu6", "wi wa wd $1 $2 $3 $4 wd $1 $2 $5 $6 wd $3 $4 $5 $6", "Transitivity axiom for equidistance (Euclidean geometry)"); axiomVec.addElement(tmpAxiom); // E. v (Bxtu /\ Byuz -> Bxvy /\ Bztv) tmpAxiom = new Axiom("eu7", "wex $6 wi wa wbt $1 $2 $3 wbt $4 $3 $5 wa wbt $1 $6 $4 wbt $5 $2 $6", "Pasch\'s axiom (Euclidean geometry)"); tmpAxiom.addDistinct("$6 $1"); tmpAxiom.addDistinct("$6 $2"); tmpAxiom.addDistinct("$6 $3"); tmpAxiom.addDistinct("$6 $4"); tmpAxiom.addDistinct("$6 $5"); axiomVec.addElement(tmpAxiom); // 3-Aug-03 - fixed a typo in this equation // E. v E. w ((Bxut /\ Byuz) /\ -. x=u -> (Bxzv /\ Bxyw) /\ Bvtw // E. 1 E. 2 ((B345 /\ B647) /\ -. 3=4 -> (B371 /\ B362) /\ B152 tmpAxiom = new Axiom("eu8", "wex $1 wex $2 wi wa wa wbt $3 $4 $5 wbt $6 $4 $7 wn weq cv $3 cv $4" + " wa wa wbt $3 $7 $1 wbt $3 $6 $2 wbt $1 $5 $2", "Euclid\'s axiom (Euclidean geometry)"); tmpAxiom.addDistinct("$1 $2"); tmpAxiom.addDistinct("$1 $3"); tmpAxiom.addDistinct("$1 $4"); tmpAxiom.addDistinct("$1 $5"); tmpAxiom.addDistinct("$1 $6"); tmpAxiom.addDistinct("$1 $7"); tmpAxiom.addDistinct("$2 $3"); tmpAxiom.addDistinct("$2 $4"); tmpAxiom.addDistinct("$2 $5"); tmpAxiom.addDistinct("$2 $6"); tmpAxiom.addDistinct("$2 $7"); axiomVec.addElement(tmpAxiom); // DxyXY /\ DyzYZ /\ DxuXU /\ DyuYU /\ Bxyz /\ BXYZ /\ -.x=y -> DzuZU // D1234 /\ D2546 /\ D1738 /\ D2748 /\ B125 /\ B346 /\ -.1=2 -> D5768 tmpAxiom = new Axiom("eu9", "wi wa wa wa wa wa wa wd $1 $2 $3 $4 wd $2 $5 $4 $6 wd $1 $7 $3 $8" + " wd $2 $7 $4 $8 wbt $1 $2 $5 wbt $3 $4 $6 wn weq cv $1 cv $2" + " wd $5 $7 $6 $8", "Five-segment axiom (Euclidean geometry)"); axiomVec.addElement(tmpAxiom); // E. z (Bxyz /\ Dyzuv) // E. 1 (B231 /\ D3145) tmpAxiom = new Axiom("eu10", "wex $1 wa wbt $2 $3 $1 wd $3 $1 $4 $5", "Axiom of segment construction (Euclidean geometry)"); tmpAxiom.addDistinct("$1 $2"); tmpAxiom.addDistinct("$1 $3"); tmpAxiom.addDistinct("$1 $4"); tmpAxiom.addDistinct("$1 $5"); axiomVec.addElement(tmpAxiom); // E. x E. y E. z (-. Bxyz /\ -. Byzx /\ -. Bzxy) tmpAxiom = new Axiom("eu11", "wex $1 wex $2 wex $3 wa wa wn wbt $1 $2 $3 wn wbt $2 $3 $1 wn wbt" + " $3 $1 $2", "Lower dimension axiom (Euclidean geometry)"); tmpAxiom.addDistinct("$1 $2"); tmpAxiom.addDistinct("$1 $3"); tmpAxiom.addDistinct("$2 $3"); axiomVec.addElement(tmpAxiom); // Dxuxv /\ Dyuyv /\ Dzuzv /\ -.u=v -> Bxyz \/ Byzx \/ Bzxy // D1213 /\ D4243 /\ D5253 /\ -.2=3 -> B145 \/ B451 \/ B514 tmpAxiom = new Axiom("eu12", "wi wa wa wa wd $1 $2 $1 $3 wd $4 $2 $4 $3 wd $5 $2 $5 $3" + " wn weq cv $2 cv $3 wo wo wbt $1 $4 $5 wbt $4 $5 $1 wbt $5 $1 $4", "Upper dimension axiom (Euclidean geometry)"); axiomVec.addElement(tmpAxiom); // E.zA.xA.y (P /\ Q -> Bzxy) -> E.zA.xA.y (P /\ Q -> Bxzy) tmpAxiom = new Axiom("eu13", "wi wex $3 wal $1 wal $2 wi wa $4 $5 wbt $3 $1 $2" + " wex $3 wal $1 wal $2 wi wa $4 $5 wbt $1 $3 $2", "Elementary continuity axiom scheme (Euclidean geometry)"); tmpAxiom.addDistinct("$1 $2"); tmpAxiom.addDistinct("$1 $3"); tmpAxiom.addDistinct("$2 $3"); tmpAxiom.addDistinct("$1 $4"); tmpAxiom.addDistinct("$3 $4"); tmpAxiom.addDistinct("$2 $5"); tmpAxiom.addDistinct("$3 $5"); axiomVec.addElement(tmpAxiom); axiomFamily[EUCLID] = axiomVec; // ************ Weak D-complete logic // Source: N. Megill & M. Bunder, "Weaker D-Complete Logics", // J. of the IGPL, Vol. 4 No. 2, pp. 215-225 (1996) axiomVec = new Vector(); axiomVec.addElement(ax_IAxiom); // ((a->a)->((c->(b->b))->(c->((a->b)->(a->b))))) tmpAxiom = new Axiom("A1w", "wi wi $1 $1 wi wi $3 wi $2 $2 wi $3 wi wi $1 $2 wi $1 $2", "Axiom A1 for weak D-complete logic"); axiomVec.addElement(tmpAxiom); // ((b->b)->((c->(a->a))->(c->((a->b)->(a->b))))) tmpAxiom = new Axiom("A2w", "wi wi $2 $2 wi wi $3 wi $1 $1 wi $3 wi wi $1 $2 wi $1 $2", "Axiom A2 for weak D-complete logic"); axiomVec.addElement(tmpAxiom); // ((c->(a->a))->((c->(b->b))->(c->((a->b)->(a->b))))) tmpAxiom = new Axiom("A3w", "wi wi $3 wi $1 $1 wi wi $3 wi $2 $2 wi $3 wi wi $1 $2 wi $1 $2", "Axiom A3 for weak D-complete logic"); axiomVec.addElement(tmpAxiom); axiomVec.addElement(rule_DAxiom); axiomFamily[WEAKD_LOGIC] = axiomVec; // ***************** END OF AXIOMS ************************************* // Determine the largest number of hypotheses maxAxiomHypotheses = 0; for (int i = 0; i < axiomFamily.length; i++) { for (int j = 0; j < axiomFamily[i].size(); j++) { if (((Axiom)(axiomFamily[i].elementAt(j))).axiomHypothesisVec.size() > maxAxiomHypotheses) { maxAxiomHypotheses = ((Axiom)(axiomFamily[i ].elementAt(j))).axiomHypothesisVec.size(); } } } // Initialize to prop calc axiomArr = buildAxiomArr(currentFamily); // Set the background color this.setBackground(BACKGROUND_COLOR); // Create buttons, add to applet, set buttons' colors //clear_button = new Button("Erase"); //clear_button.setForeground(Color.black); //clear_button.setBackground(Color.lightGray); //this.add(clear_button); proof_exit_button = new Button("Hide Proof Information"); proof_exit_button.setActionCommand("proof_exit_button"); proof_exit_button.addActionListener(this); info_exit_button = new Button("Exit Axiom Information"); info_exit_button.setActionCommand("info_exit_button"); info_exit_button.addActionListener(this); // Create option selection menu buildOptionChoices(); // Create axiom selection menu buildAxiomChoices(); } // init // Builds the axiomArr array based on the chosen logic familiy // and adds to it all user theorems that are valid in that // logic family static final Axiom[] buildAxiomArr(int logicFamily) { Vector axiomVec = (Vector)(axiomFamily[logicFamily].clone()); // Build a string with all axiom labels String axiomLabels = " "; if (userTheorems.size() != 0) { // Only build label list if it will be used for (int i = 0; i < axiomVec.size(); i++) { axiomLabels = axiomLabels + ((Axiom)(axiomVec.elementAt(i))).label + " "; } } // For each user theorem, accept it only if all steps of each proof // are in the axiomLabels string for (int i = 0; i < userTheorems.size(); i++) { Axiom userTh = (Axiom)(userTheorems.elementAt(i)); String userProof = " " + userTh.proof + " "; int position0 = 1; int position = userProof.indexOf(' ', position0); boolean validProof = true; while (position != -1) { String userProofStepLabel = userProof.substring(position0 - 1, position + 1); if (axiomLabels.indexOf(userProofStepLabel) == -1 // 5-Jun-2002 (ndm) The condition below was added in case the // users proof contains hypotheses. && userProofStepLabel.charAt(1) != '$') // The userProofStepLabel is surrounded by spaces, so we match // $hypnn starting at position 1, not 0 // future: make sure that $ is not allowed in user theorem // names if an enhancement is made to accept user names { // If it's not an axiom or hypothesis, it's not a valid theorem for // this logic family, so we don't put it in the list of choices // available to the user. validProof = false; break; } position0 = position + 1; position = userProof.indexOf(' ', position0); } if (validProof) { axiomVec.insertElementAt(userTh, 0); // Add label since a later proof could use it axiomLabels = axiomLabels + userTh.label + " "; } } // for i Axiom[] axArr = new Axiom[axiomVec.size()]; axiomVec.copyInto(axArr); return axArr; } public void actionPerformed(ActionEvent e) { if (e.getActionCommand().equals("proof_exit_button")) { this.remove(proof_text); this.remove(proof_exit_button); proofInfoModeFlag = false; /* [sound] */ audioName = "wzzz"; // Sound effect /* [sound] */ // Play sound if any /* [sound] */ playAudio(); // Rebuild options buildOptionChoices(); // Rebuild axiom selection menu and redisplay choice buildAxiomChoices(); // Repaint screen paint(this.getGraphics()); // return true; (actionPerformed returns void) } else if (e.getActionCommand().equals("info_exit_button")) { this.setBackground(BACKGROUND_COLOR); this.remove(info_exit_button); axiomInfoModeFlag = false; /* [sound] */ audioName = "wzzz"; // Sound effect /* [sound] */ // Play sound if any /* [sound] */ playAudio(); // Rebuild options buildOptionChoices(); // Rebuild axiom selection menu and redisplay choice buildAxiomChoices(); // Repaint screen paint(this.getGraphics()); // return true; (actionPerformed returns void) } } public void itemStateChanged(ItemEvent e) { if (e.getItemSelectable() == option_choices) { boolean rebuildFlag = false; if (e.getItem() == "Undo") { redoStack.push(currentState.makeClone()); currentState = (State)(undoStack.pop()); userTheorems = currentState.userThVec; currentFamily = currentState.currentFam; axiomArr = buildAxiomArr(currentFamily); /* [sound] */ audioName = "zoom"; // Sound effect rebuildFlag = true; } else if (e.getItem() == "Redo") { undoStack.push(currentState.makeClone()); currentState = (State)(redoStack.pop()); /* [sound] */ audioName = "whoosh"; // Sound effect rebuildFlag = true; } else if (e.getItem() == "Rotate Stack" || e.getItem() == "Swap Stack Top") { /* [sound] */ audioName = "gate"; // Sound effect undoStack.push(currentState.makeClone()); redoStack = new Stack(); int iEnd = currentState.assertionVec.size() - 1; int iStart; if (e.getItem() == "Rotate Stack") { iStart = 0; } else { iStart = iEnd - 1; } String tmpStr = (String)(currentState.assertionVec.elementAt(iStart)); String tmpPStr = (String)(currentState.proofVec.elementAt(iStart)); for (int j = iStart; j < iEnd; j++) { currentState.assertionVec.setElementAt( currentState.assertionVec.elementAt(j + 1), j); currentState.proofVec.setElementAt( currentState.proofVec.elementAt(j + 1), j); } currentState.assertionVec.setElementAt(tmpStr, iEnd); currentState.proofVec.setElementAt(tmpPStr, iEnd); rebuildFlag = true; } else if (e.getItem() == "Delete Stack Top") { /* [sound] */ audioName = "ouch"; // Sound effect undoStack.push(currentState.makeClone()); redoStack = new Stack(); currentState.assertionVec.removeElementAt( currentState.assertionVec.size() - 1); currentState.proofVec.removeElementAt( currentState.proofVec.size() - 1); if (currentState.assertionVec.size() != // Should never be different! currentState.proofVec.size()) System.out.println("Bug #2"); // normalize to trim any distinct variable pairs that become unused currentState.normalize(); rebuildFlag = true; } else if (e.getItem() == "Erase Stack") { /* [sound] */ audioName = "splat"; // Sound effect undoStack.push(currentState.makeClone()); redoStack = new Stack(); currentState = new State(); rebuildFlag = true; } else if (e.getItem() == "Erase All") { /* [sound] */ audioName = "bomb"; // Sound effect //init(); // rebuild is done in init() undoStack.push(currentState.makeClone()); redoStack = new Stack(); userTheorems = new Vector(); currentState = new State(); currentFamily = PROP_CALC; axiomArr = buildAxiomArr(currentFamily); rebuildFlag = true; //paint(this.getGraphics()); } else if (e.getItem() == "Proof Information") { /* [sound] */ audioName = "wzzz2"; // Sound effect proofInfoModeFlag = true; rebuildFlag = true; // Need to rebuild option choice & display proof } else if (e.getItem() == "Axiom Information") { /* [sound] */ audioName = "wzzz2"; // Sound effect axiomInfoModeFlag = true; infoModeAxiomToShow = -1; // means no axiom selected by user yet rebuildFlag = true; // We will re-paint in this special mode this.setBackground(INFO_BACKGROUND_COLOR); } else if (e.getItem() == "Select Logic Family") { /* [sound] */ audioName = "gate"; // Sound effect this.removeAll(); CheckboxGroup cg = new CheckboxGroup(); for (int i = 0; i < FAMILIES; i++) { boolean enable; if (i == currentFamily) enable = true; else enable = false; logic_select[i] = new Checkbox(familyName[i], cg, enable); this.add(logic_select[i]); logic_select[i].addItemListener(this); } selectLogicModeFlag = true; /* [sound] */ // Play sound if any /* [sound] */ playAudio(); paint(this.getGraphics()); // return true; (itemStateChanged returns void) } else if (e.getItem() == "Add Hypothesis") { /* [sound] */ audioName = "clink"; // Sound effect undoStack.push(currentState.makeClone()); redoStack = new Stack(); currentState.addHyp(); rebuildFlag = true; } else if (e.getItem() == "Save as Axiom") { /* [sound] */ audioName = "beep_spring"; // Sound effect undoStack.push(currentState.makeClone()); redoStack = new Stack(); // Save theorem at stack top as a new axiom - must rebuild array // with greater bound userTheorems.addElement(new Axiom(currentState)); currentState.userThVec = userTheorems; axiomArr = buildAxiomArr(currentFamily); // Update the largest number of hypotheses if (axiomArr[0].axiomHypothesisVec.size() > maxAxiomHypotheses) { maxAxiomHypotheses = axiomArr[0].axiomHypothesisVec.size(); } // Re-display screen so user's new axiom will become an axiom pick rebuildFlag = true; } else if (e.getItem() == "Refresh Screen") { rebuildFlag = true; /* [sound] */ } else if (e.getItem() == "Turn Sound On") { /* [sound] */ enableAudioFlag = true; /* [sound] */ audioName = "whoosh"; /* [sound] */ rebuildFlag = true; /* [sound] */ } else if (e.getItem() == "Turn Sound Off") { /* [sound] */ enableAudioFlag = false; /* [sound] */ rebuildFlag = true; } /* [sound] */ // Play sound if any /* [sound] */ playAudio(); if (rebuildFlag) { // Rebuild options buildOptionChoices(); // Rebuild axiom selection menu and redisplay choice buildAxiomChoices(); // If in display proof mode, put proof after choice if (proofInfoModeFlag) { proof_text = new TextArea( "The top stack entry is:\n\n", 20, 65); // Future: in Java 1.1 add: , SCROLLBARS_VERTICAL_ONLY); proof_text.append(" " + PrimFormula.getDisplay( (String)(currentState.assertionVec.lastElement()), false)); proof_text.append( "\n\nTo reconstruct the" + " top stack entry, enter axioms in this order:\n\n"); proof_text.append(" " + (String)(currentState.proofVec.lastElement())); proof_text.setBackground(PROOF_BACKGROUND_COLOR); // Display fleshed-out proof detail proof_text.append("\n\nDetailed proof:\n\n"); State proofInfoState = State.buildProofInfoState(currentState); for (int i = 0; i < proofInfoState.assertionVec.size(); i++) { proof_text.append(" " + ((String)(proofInfoState.proofVec.elementAt(i))) + " " + PrimFormula.getDisplay( (String)(proofInfoState.assertionVec.elementAt(i)), false) + "\n"); } if (proofInfoState.distinctVarVec.size() > 0) { proof_text.append("\nDistinct variable pairs for this proof:\n\n"); for (int i = 0; i < proofInfoState.distinctVarVec.size(); i++) { proof_text.append(" "); for (int j = 0; j < 2; j++) { short v = (short)(((String)( proofInfoState.distinctVarVec.elementAt(i))).charAt(j)); // We assume type is already assigned, so 0 is OK proof_text.append(VariableName.name(v, (short)0) + " "); } } } this.add(proof_text); } // Repaint screen paint(this.getGraphics()); } } else if (e.getItemSelectable() == axiom_choices) { int choice; // Lookup what the choice corresponds to choice = ((Integer)(axiomChoiceVec.elementAt( axiom_choices.getSelectedIndex()))).intValue(); /* [sound] */ // Sound effects /* [sound] */ audioName = "drip"; /* [sound] */ if (choice > 0) { /* [sound] */ if (axiomArr[choice].label.equals("ax-inf")) audioName = "hypspc"; /* [sound] */ else if (axiomArr[choice].label.equals("ax-ac")) audioName = "ni"; /* [sound] */ } /* [sound] */ // End sound effects if (axiomInfoModeFlag) { infoModeAxiomToShow = choice; } else { if (choice < 0) { // Push undo stack undoStack.push(currentState.makeClone()); redoStack = new Stack(); // It's a hypothesis; add it to the assertion stack currentState.pushAssertion( (String)(currentState.hypothesisVec.elementAt(- choice - 1)), // The proof is one step, just the hypothesis "$hyp" + String.valueOf(- choice)); } else { /* [sound] */ // Sound effects /* [sound] */ int rAudio = axiomArr[choice].axiomHypothesisVec.size(); /* [sound] */ int aAudio = currentState.assertionVec.size(); /* [sound] */ if (rAudio == aAudio && rAudio > 1) audioName = "bart.aye_carumba"; /* [sound] */ else if (rAudio == 1) audioName = "bubble1"; // ax-gen /* [sound] */ else if (rAudio > 0) audioName = "boing"; // ax-mp /* [sound] */ // End sound effects // Push undo stack - no need to clone since unify does this undoStack.push(currentState); redoStack = new Stack(); // It's a axiom - it will always unify since that was determined // when choice list was built currentState = Unification.unify(axiomArr[choice], currentState, false); // Squish down variables and trim unused distinct var pairs currentState.normalize(); } // Rebuild option selection buildOptionChoices(); // Rebuild axiom selection menu and redisplay choice buildAxiomChoices(); } // not info mode // (If it's info mode, menus will not change until we exit it; no need // to rebuild) /* [sound] */ // Play sound if any /* [sound] */ playAudio(); // Repaint screen paint(this.getGraphics()); // return true; (itemStateChanged returns void) // end if (event.target == axiom_choices) } else { for (int i = 0; i < FAMILIES; i++) { if (e.getItemSelectable() == logic_select[i]) { selectLogicModeFlag = false; if (currentFamily != i) { // User selected a new logic family /* [sound] */ audioName = "clink"; // Sound effect undoStack.push(currentState.makeClone()); redoStack = new Stack(); currentFamily = i; axiomArr = buildAxiomArr(currentFamily); currentState = new State(); } /* [sound] */ // Play sound if any /* [sound] */ playAudio(); // Rebuild option selection buildOptionChoices(); // Rebuild axiom selection menu and redisplay choice buildAxiomChoices(); // Repaint screen paint(this.getGraphics()); // return true; (itemStateChanged returns void) } } } } // Build list of choices from axiom menu void buildOptionChoices() { // Remove everything at once for less display glitches this.removeAll(); if (proofInfoModeFlag) { this.add(proof_exit_button); return; } else if (axiomInfoModeFlag) { this.add(info_exit_button); return; } else { option_choices = new Choice(); option_choices.addItemListener(this); if (!undoStack.empty()) { option_choices.addItem("Undo"); } if (currentState.assertionVec.size() > 1) { option_choices.addItem("Swap Stack Top"); option_choices.addItem("Rotate Stack"); } if (currentState.assertionVec.size() > 0) { option_choices.addItem("Delete Stack Top"); } if (currentState.assertionVec.size() > 0 || currentState.hypothesisVec.size() > 0) { option_choices.addItem("Erase Stack"); } //if (currentState.assertionVec.size() > 0 // || currentState.hypothesisVec.size() > 0 // || !undoStack.empty() // || numAxioms != builtInNumAxioms) { // option_choices.addItem("Erase All"); //} if (currentState.assertionVec.size() > 0) { option_choices.addItem("Proof Information"); } option_choices.addItem("Axiom Information"); option_choices.addItem("Add Hypothesis"); option_choices.addItem("Select Logic Family"); if (currentState != null && currentState.assertionVec.size() > 0) { option_choices.addItem("Save as Axiom"); } // User workaround for Java graphics bugs option_choices.addItem("Refresh Screen"); /* [sound] */ if (enableAudioFlag) { /* [sound] */ option_choices.addItem("Turn Sound Off"); /* [sound] */ } else { /* [sound] */ // Comment out next line to disable audio effects (if you don't have /* [sound] */ // the .au files) /* [sound] */ option_choices.addItem("Turn Sound On"); /* [sound] */ } } this.add(option_choices); } // Build option choices // Build list of choices from axiom menu void buildAxiomChoices() { State dummyState; String menuString = ""; String menuFormula = ""; if (proofInfoModeFlag) { return; // Disable selection in proof display mode } if (axiomInfoModeFlag) { axiom_label.setBackground(INFO_BACKGROUND_COLOR); } else { axiom_label.setBackground(BACKGROUND_COLOR); } this.add(axiom_label); axiomChoiceVec = new Vector(); axiom_choices = new Choice(); axiom_choices.addItemListener(this); if (currentState.hypothesisVec.size() != 0) { // If there are hypotheses, do a dummy run-thru of assertions and // hypotheses to get desired variable names for axiom choice menu VariableName.init(); for (int i = currentState.assertionVec.size() - 1; i >= 0; i--) { String dummy = PrimFormula.getDisplay( (String)(currentState.assertionVec.elementAt(i)), false); } for (int i = currentState.hypothesisVec.size() - 1; i >= 0; i--) { String dummy = PrimFormula.getDisplay( (String)(currentState.hypothesisVec.elementAt(i)), false); } } // Put any user hypotheses first // Variable names have not been reinitialized here; we want to use // the names in the currentState display for best user info if (!axiomInfoModeFlag) { for (int i = 0; i < currentState.hypothesisVec.size(); i++) { menuString = "1 $hyp" + String.valueOf(i + 1) + " " + PrimFormula.getDisplay( (String)(currentState.hypothesisVec.elementAt(i)), false); if (menuString.length() > MAX_AXIOM_CHOICE_LEN) { // Trim to size menuString = menuString.substring(0, MAX_AXIOM_CHOICE_LEN - 3) + "..."; } axiom_choices.addItem(menuString); axiomChoiceVec.addElement(new Integer(- i - 1)); } } // For each axiom, if it unifies with the state stack, add it in // Scan in reverse order of number of hypotheses, so axioms that reduce // stack the most will be displayed first // Note: in info mode we show *all* axioms in their natural order, whether // or not they unify for (int hyps = maxAxiomHypotheses; hyps >= 0; hyps--) { if (axiomInfoModeFlag && hyps > 0) continue; for (int i = 0; i < axiomArr.length; i++) { if (!axiomInfoModeFlag && axiomArr[i].axiomHypothesisVec.size() != hyps) continue; if (hyps == 0) { // (or axiomInfoModeFlag - see continue logic above) // If there are no hypotheses, don't bother to unify for speedup menuString = axiomArr[i].menuEntry; // use pre-computed entry for speed } else { dummyState = Unification.unify(axiomArr[i], currentState, false); if (dummyState == null) continue; // Unification not possible menuFormula = dummyState.getStackTop(); VariableName.init(); // Initialize so types don't get mixed up // Show how much stack will grow, name of axiom, & the top of the // stack that would result menuString = String.valueOf(1 - hyps) + " " + axiomArr[i].label + " " + PrimFormula.getDisplay(menuFormula, false); if (menuString.length() > MAX_AXIOM_CHOICE_LEN) { // Trim to size menuString = menuString.substring(0, MAX_AXIOM_CHOICE_LEN - 3) + "..."; } } axiom_choices.addItem(menuString); axiomChoiceVec.addElement(new Integer(i)); } /* next i */ } /* next hyps */ this.add(axiom_choices); } public void paint(Graphics g) { String token; FontMetrics fm; // validate makes an added Component show up in the display // (not documented in Java spec?) this.validate(); VariableName.init(); // Initialize so types don't get mixed up // Clear screen Rectangle r = this.getBounds(); g.setColor(this.getBackground()); g.fillRect(r.x, r.y, r.width, r.height); currentX = X_INIT; currentY = 3 * Y_INCREMENT; // Display title g.setFont(new Font("Dialog", Font.PLAIN, FONT_SIZE)); // Apply watermark to background // \u00a9 = copyright symbol token = "Metamath Solitaire \u00a9 2003 (GPL) Norman Megill nm" + "@" + "alum.mit.edu"; if (axiomInfoModeFlag) { g.setColor(Color.magenta); } else { g.setColor(Color.cyan); } fm = g.getFontMetrics(); g.drawString(token, (r.width - fm.stringWidth(token))/2, r.height - 10); // Display type colors g.setFont(new Font("Dialog", Font.PLAIN, FONT_SIZE)); g.setColor(Color.black); if (selectLogicModeFlag) { token = "Click on the logic family you want to use."; g.drawString(token, (r.width - fm.stringWidth(token))/2, r.height / 2); return; } g.setFont(new Font("Dialog", Font.BOLD, FONT_SIZE)); token = familyName[currentFamily]; g.drawString(token, X_INIT, currentY); fm = g.getFontMetrics(); currentX += fm.stringWidth(token) + 2 * FONT_SIZE; g.setFont(new Font("Dialog", Font.PLAIN, FONT_SIZE)); if (axiomInfoModeFlag && infoModeAxiomToShow == -1) { currentY = 5 * Y_INCREMENT; // User has not selected an axiom yet token = "To see information about an axiom, choose it from the 'Axioms' menu."; g.drawString(token, X_INIT, currentY); return; } if (!axiomInfoModeFlag && currentState.assertionVec.size() == 0 && currentState.hypothesisVec.size() == 0) { // There is nothing to display yet. Just after startup or erase. currentY = 5 * Y_INCREMENT; g.drawString( "The 'Axioms' menu shows how much the stack will grow, the axiom name,", X_INIT, currentY); currentY += Y_INCREMENT; g.drawString( "and as much of the axiom as can be displayed.", X_INIT, currentY); currentY += 2 * Y_INCREMENT; g.drawString( "Select repeatedly from the 'Axioms' menu. The stack will grow and shrink", X_INIT, currentY); currentY += Y_INCREMENT; g.drawString( "with theorems. The goal is to end up with a single stack entry containing", X_INIT, currentY); currentY += Y_INCREMENT; g.drawString( "a nice theorem. You can clip out its proof with 'Proof Information'.", X_INIT, currentY); currentY += 2 * Y_INCREMENT; if (currentFamily == PROP_CALC) { g.drawString( "Example: ax-1, ax-1, ax-2, ax-mp, ax-mp proves (P->P).", X_INIT, currentY); } if (currentFamily == EUCLID) { currentY += Y_INCREMENT; g.drawString( "For Euclidean geometry, Bxyz means \"y lies between x and z\", and Dxyzw means", X_INIT, currentY); currentY += Y_INCREMENT; g.drawString( "\"x is as distant from y as z is from w\".", X_INIT, currentY); currentY += Y_INCREMENT; currentY += Y_INCREMENT; g.drawString( "Reference: A. Tarski, in The Axiomatic Method (ed. Henkin et. al.) (1959), p. 19", X_INIT, currentY); } currentY += Y_INCREMENT; if (currentFamily == IMPL_LOGIC) { g.drawString( "Reference: R. Hindley and D. Meredith, J. Symb. Logic 55, 90-105 (1990)", X_INIT, currentY); } if (currentFamily == INTUIT_LOGIC) { g.drawString( "Reference: T. Thatcher Robinson, J. Symb. Logic 33, 265-270 (1968)", X_INIT, currentY); } if (currentFamily == MODAL_LOGIC) { g.drawString( "Reference: http://www-formal.stanford.edu/pub/jmc/mcchay69/node22.html", X_INIT, currentY); } if (currentFamily == GODEL_LOGIC) { g.drawString( "Reference: G. Boolos and R. Jeffrey, Computability and Logic (1989), ch. 27", X_INIT, currentY); } if (currentFamily == QUANTUM_LOGIC) { g.drawString( "Reference: M. Pavicic, Int. J. of Theoretical Physics 32, 1481-1505 (1993)", X_INIT, currentY); } if (currentFamily == WEAKD_LOGIC) { g.drawString( "Reference: http://www.mpi-sb.mpg.de/igpl/Bulletin/V4-2/#Megill", X_INIT, currentY); } return; } token = "Colors of variable types:"; g.drawString(token, currentX, currentY); fm = g.getFontMetrics(); currentX += fm.stringWidth(token) + 2 * FONT_SIZE; g.setFont(MATH_PLAIN_FONT); fm = g.getFontMetrics(); //for (int i = 0; i < 4; i++) { // Future for (int i = 0; i < 3; i++) { Color c = Color.black; switch (i) { case 0: c = Color.blue; token = "wff"; break; case 1: c = Color.red; if (currentFamily == EUCLID) token = "point"; else token = "set"; break; case 2: c = Color.magenta; token = "class"; break; case 3: c = DARK_GREEN; token = "digit"; break; } g.setColor(c); g.drawString(token, currentX, currentY); currentX += fm.stringWidth(token) + 2 * FONT_SIZE; // Only show wff color for propositional families if (currentFamily != PRED_CALC && currentFamily != PRED_DEFS && currentFamily != SET_THEORY && currentFamily != SET_DEFS && currentFamily != EUCLID && i == 0) break; // Show classes only for set theory definitions if (currentFamily != SET_DEFS && i == 1) break; } // Display stack (or requested axiom in info mode) String axiomOrTheorem = "axiom"; if (currentState.assertionVec.size() != 0 || axiomInfoModeFlag) { currentY += Y_INCREMENT * 3 / 2; g.setFont(new Font("Dialog", Font.PLAIN, FONT_SIZE)); g.setColor(Color.black); if (axiomInfoModeFlag) { if (!axiomArr[infoModeAxiomToShow].proof.equals("")) { axiomOrTheorem = "theorem"; } g.setFont(new Font("Dialog", Font.BOLD, FONT_SIZE)); token = "Information for " + axiomOrTheorem + " " + axiomArr[infoModeAxiomToShow].label; g.drawString(token, X_INIT, currentY); currentY += Y_INCREMENT; g.setFont(new Font("Dialog", Font.PLAIN, FONT_SIZE)); token = "Description: " + axiomArr[infoModeAxiomToShow].description; g.drawString(token, X_INIT, currentY); if (!axiomArr[infoModeAxiomToShow].proof.equals("")) { currentY += Y_INCREMENT; token = "Proof: " + axiomArr[infoModeAxiomToShow].proof; g.drawString(token, X_INIT, currentY); } currentY += Y_INCREMENT * 3 / 2; token = "Assertion made by this " + axiomOrTheorem + ":"; } else { if (currentState.hypothesisVec.size() == 0) { token = "Assertion stack (each line is a theorem scheme of this logic family):"; } else { token = "Assertion stack (each line is an inference from the hypotheses):"; } } g.drawString(token, X_INIT, currentY); g.setFont(MATH_PLAIN_FONT); VariableName.init(); // Initialize name map so var's will be renumbered if (axiomInfoModeFlag) { currentY += Y_INCREMENT; DrawSymbols.drawFormula(g, currentY, axiomArr[infoModeAxiomToShow].assertion); } else { // Display from top of stack down for (int i = currentState.assertionVec.size() - 1; i >= 0; i--) { currentY += Y_INCREMENT; DrawSymbols.drawFormula(g, currentY, (String)(currentState.assertionVec.elementAt(i))); } } } // Display hypotheses if ((!axiomInfoModeFlag && currentState.hypothesisVec.size() != 0) || (axiomInfoModeFlag && axiomArr[infoModeAxiomToShow].axiomHypothesisVec.size() != 0)) { currentY += Y_INCREMENT * 3 / 2; g.setFont(new Font("Dialog", Font.PLAIN, FONT_SIZE)); g.setColor(Color.black); if (axiomInfoModeFlag) { token = "Hypotheses for this " + axiomOrTheorem + ":"; // in reverse order } else { token = "Hypotheses for the assertions in the stack:"; // in reverse order } g.drawString(token, X_INIT, currentY); g.setFont(MATH_PLAIN_FONT); if (axiomInfoModeFlag) { // Normal order //for (int i = 0; i // < axiomArr[infoModeAxiomToShow].axiomHypothesisVec.size(); // i++) { // Reverse order for (int i = axiomArr[infoModeAxiomToShow].axiomHypothesisVec.size() - 1; i >= 0; i--) { currentY += Y_INCREMENT; DrawSymbols.drawFormula(g, currentY, (String)(axiomArr[infoModeAxiomToShow ].axiomHypothesisVec.elementAt(i))); } } else { // Normal order //for (int i = 0; i < currentState.hypothesisVec.size(); i++) { // Reverse order for (int i = currentState.hypothesisVec.size() - 1; i >= 0; i--) { currentY += Y_INCREMENT; DrawSymbols.drawFormula(g, currentY, (String)(currentState.hypothesisVec.elementAt(i))); } } } // Display distinct variable pairs if ((!axiomInfoModeFlag && currentState.distinctVarVec.size() != 0) || (axiomInfoModeFlag && axiomArr[infoModeAxiomToShow].axiomDistVarVec.size() != 0)) { currentY += Y_INCREMENT + Y_INCREMENT / 2; g.setFont(new Font("Dialog", Font.PLAIN, FONT_SIZE)); g.setColor(Color.black); g.drawString( "Substitutions for these variable pairs may not have variables in", X_INIT, currentY); currentY += Y_INCREMENT; if (axiomInfoModeFlag) { token = "common for an instance of the " + axiomOrTheorem + " to remain valid:"; } else { token = "common for the assertions to remain valid:"; } g.drawString(token, X_INIT, currentY); g.setFont(MATH_PLAIN_FONT); currentY += Y_INCREMENT; Vector dVarVec; if (axiomInfoModeFlag) { dVarVec = axiomArr[infoModeAxiomToShow].axiomDistVarVec; } else { dVarVec = currentState.distinctVarVec; } currentY = DrawSymbols.drawDistinct(g, currentY, dVarVec); } } // paint /* [sound] */ // Sound effects /* [sound] */ public void playAudio() { /* [sound] */ if (enableAudioFlag && audioName != null) { /* [sound] */ // Find out if we've already read this one in so we don't read it again /* [sound] */ // (Is this really necessary or does Java cache the stuff internally?) /* [sound] */ AudioClip a = null; /* [sound] */ for (int i = 0; i < audioSaveNameVec.size(); i++) { /* [sound] */ if (((String)(audioSaveNameVec.elementAt(i))).equals(audioName)) { /* [sound] */ a = (AudioClip)(audioSaveClipVec.elementAt(i)); /* [sound] */ break; /* [sound] */ } /* [sound] */ } /* [sound] */ if (a == null) { /* [sound] */ a = getAudioClip(getCodeBase(), audioName + ".au"); /* [sound] */ audioSaveNameVec.addElement(audioName); /* [sound] */ audioSaveClipVec.addElement(a); /* [sound] */ } /* [sound] */ a.play(); /* [sound] */ } /* [sound] */ audioName = null; /* [sound] */ } // playAudio } // class mm // Formula drawing final class DrawSymbols { static Graphics g; static int currentX; static int currentY; static FontMetrics fm; static short lastTokenType; // Box coordinates for special characters static int leftX; static int rightX; static int bottomY; static int topY; static int middleX; static int middleY; static int one4thX; static int three4thX; static int one4thY; static int three4thY; private static final void setBox(int width) { leftX = currentX; rightX = currentX + width; bottomY = currentY; topY = currentY - fm.getHeight() * 2 / 3; middleX = (leftX + rightX) / 2; middleY = (bottomY + topY) / 2; one4thX = (leftX + middleX) / 2; three4thX = (middleX + rightX) / 2; one4thY = (bottomY + middleY) / 2; three4thY = (middleY + topY) / 2; } private static final void drawToken(String token, short type) { String character = ""; Color c = Color.black; // -1 = connective if (type == (short)(-1)) { // Connective g.setColor(c); // Compose special tokens if (token.equals("A.")) { // forall setBox(fm.stringWidth("M")); g.drawLine(leftX, topY, middleX, bottomY); g.drawLine(middleX, bottomY, rightX, topY); g.drawLine(one4thX, middleY, three4thX, middleY); } else if (token.equals("->")) { // arrow setBox(fm.stringWidth("M") * 2); g.drawLine(leftX, middleY, rightX, middleY); g.drawLine(middleX, topY, rightX, middleY); g.drawLine(middleX, bottomY, rightX, middleY); } else if (token.equals("<->")) { // double arrow setBox(fm.stringWidth("M") * 3); g.drawLine(leftX, middleY, rightX, middleY); g.drawLine(one4thX, topY, leftX, middleY); g.drawLine(one4thX, bottomY, leftX, middleY); g.drawLine(three4thX, topY, rightX, middleY); g.drawLine(three4thX, bottomY, rightX, middleY); } else if (token.equals("\\/")) { // vee setBox(fm.stringWidth("M")); g.drawLine(leftX, three4thY, middleX, bottomY); g.drawLine(rightX, three4thY, middleX, bottomY); } else if (token.equals("/\\")) { // wedge setBox(fm.stringWidth("M")); g.drawLine(leftX, bottomY, middleX, three4thY); g.drawLine(rightX, bottomY, middleX, three4thY); } else if (token.equals("E.")) { // exists setBox(fm.stringWidth("M")); g.drawLine(leftX, bottomY, rightX, bottomY); g.drawLine(leftX, middleY, rightX, middleY); g.drawLine(leftX, topY, rightX, topY); g.drawLine(rightX, topY, rightX, bottomY); } else if (token.equals("-.")) { // not setBox(fm.stringWidth("M")); g.drawLine(leftX, middleY, rightX, middleY); g.drawLine(rightX, middleY, rightX, bottomY); } else if (token.equals("e.")) { // epsilon setBox(fm.stringWidth("M")); g.drawLine(leftX, middleY, middleX, topY); g.drawLine(middleX, topY, rightX, topY); g.drawLine(leftX, middleY, middleX, bottomY); g.drawLine(middleX, bottomY, rightX, bottomY); g.drawLine(leftX, middleY, three4thX, middleY); } else if (token.equals("u.")) { // union setBox(fm.stringWidth("M")); g.drawLine(leftX, three4thY, leftX, one4thY); g.drawLine(leftX, one4thY, middleX, bottomY); g.drawLine(middleX, bottomY, rightX, one4thY); g.drawLine(rightX, one4thY, rightX, three4thY); } else if (token.equals("i^i")) { // intersection setBox(fm.stringWidth("M")); g.drawLine(leftX, bottomY, leftX, middleY); g.drawLine(leftX, middleY, middleX, three4thY); g.drawLine(middleX, three4thY, rightX, middleY); g.drawLine(rightX, middleY, rightX, bottomY); } else if (token.equals("U.")) { // Union setBox(fm.stringWidth("M")); g.drawLine(leftX, topY, leftX, one4thY); g.drawLine(leftX, one4thY, middleX, bottomY); g.drawLine(middleX, bottomY, rightX, one4thY); g.drawLine(rightX, one4thY, rightX, topY); } else if (token.equals("|^|")) { // Intersection setBox(fm.stringWidth("M")); g.drawLine(leftX, bottomY, leftX, three4thY); g.drawLine(leftX, three4thY, middleX, topY); g.drawLine(middleX, topY, rightX, three4thY); g.drawLine(rightX, three4thY, rightX, bottomY); } else if (token.equals("(_")) { // subset setBox(fm.stringWidth("M")); g.drawLine(rightX, topY, leftX, topY); g.drawLine(leftX, topY, leftX, one4thY); g.drawLine(leftX, one4thY, rightX, one4thY); g.drawLine(leftX, bottomY, rightX, bottomY); } else if (token.equals("(/)")) { // empty set setBox(fm.stringWidth("M")); g.drawOval(leftX, topY, rightX - leftX, bottomY - topY); g.drawLine(leftX, bottomY, rightX, topY); } else if (token.equals("[]")) { // box setBox(fm.stringWidth("M")); g.drawRect(leftX, topY, rightX - leftX, bottomY - topY); } else if (token.equals("<>")) { // diamond setBox(fm.stringWidth("M")); g.drawLine(leftX, middleY, middleX, topY); g.drawLine(middleX, topY, rightX, middleY); g.drawLine(rightX, middleY, middleX, bottomY); g.drawLine(middleX, bottomY, leftX, middleY); } else if (token.equals("_|_")) { // upside-down T (false) setBox(fm.stringWidth("M")); g.drawLine(leftX, bottomY, rightX, bottomY); g.drawLine(middleX, bottomY, middleX, topY); } else { // Output as is g.drawString(token, currentX, currentY); rightX = currentX + fm.stringWidth(token); } currentX = rightX + 1; } else { // Variable switch (type) { case 0: c = Color.blue; break; // wff case 1: c = Color.red; break; // set (var) case 2: c = Color.magenta; break; // class case 3: c = mm.DARK_GREEN; break; // digit } g.setColor(c); // Use italics for variables //g.setFont(mm.MATH_ITALIC_FONT); // Put extra space between two variables for better appearance if (lastTokenType >= 0) currentX += mm.WHITE_SPACE / 2; g.drawString(token, currentX, currentY); currentX += fm.stringWidth(token); // Restore to non-italic //g.setFont(mm.MATH_PLAIN_FONT); } lastTokenType = type; //for (int i = 0; i < token.length(); i++) { // character = token.substring(i, i + 1); // g.drawString(character, currentX, currentY); // currentX += fm.stringWidth(character) + mm.CHAR_SPACE; //} currentX += mm.WHITE_SPACE; } static final void drawFormula(Graphics wg, int wcurrentY, String formula) { String token; int position0; int position; short varNum; short varType; int p2; lastTokenType = (short)(-1); /* Init */ g = wg; fm = g.getFontMetrics(); currentY = wcurrentY; currentX = mm.X_INIT; formula = PrimFormula.getDisplay(formula, true); // true returns variables // as $var:type formula = formula + " "; position0 = 0; position = formula.indexOf(' '); while (position != -1) { token = formula.substring(position0, position); if (token.charAt(0) == '$') { // Variable p2 = token.indexOf(':'); varNum = (short)Integer.parseInt(token.substring(1, p2)); varType = (short)Integer.parseInt(token.substring(p2 + 1)); drawToken(VariableName.name(varNum, varType), varType); } else { // Connective drawToken(token, (short)(-1)); } position0 = position + 1; position = formula.indexOf(' ', position0); } } // Draw the distinct variable pair list // Returns the new currentY static final int drawDistinct(Graphics wg, int wcurrentY, Vector distinctVarVec) { short v; lastTokenType = (short)(-1); /* Init */ g = wg; fm = g.getFontMetrics(); currentY = wcurrentY; currentX = mm.X_INIT; for (int i = 0; i < distinctVarVec.size(); i++) { for (int j = 0; j < 2; j++) { v = (short)(((String)(distinctVarVec.elementAt(i))).charAt(j)); // We assume type is already assigned, so 0 is OK */ drawToken(VariableName.name(v, (short)0), VariableName.type(v)); currentX += 4; } currentX += 20; // New line every 10 pairs if ((i + 1) % 10 == 0) { currentX = mm.X_INIT; currentY += mm.Y_INCREMENT; } } return currentY; } } // class DrawSymbols // Primitive formula handler final class PrimFormula { // Get shortest primitive formula static final String pformula(String formula, int start) { String subformula; int position; short connNum; int i; if ((short)(formula.charAt(start)) > 0) { // It's a variable return formula.substring(start, start + 1); } else { // It's a connective connNum = (short)(formula.charAt(start)); connNum = (short)(- (connNum + 1)); subformula = formula.substring(start, start + 1); position = start; for (i = 0; i < mm.connectiveArr[connNum].argtypes.length; i++) { position = start + subformula.length(); subformula = subformula + pformula(formula, position); } return subformula; } } // pformula // Return variable/connective types in a formula string static final String getTypes(String formula, int start) { String typesList; int position; short connNum; short typeNum; int i; if ((short)(formula.charAt(start)) > 0) { // It's a variable; we don't know the type yet; default to wff return String.valueOf((char)0); } else { // It's a connective connNum = (short)(formula.charAt(start)); connNum = (short)(- (connNum + 1)); typeNum = mm.connectiveArr[connNum].type; typesList = String.valueOf((char)typeNum); position = start; for (i = 0; i < mm.connectiveArr[connNum].argtypes.length; i++) { position = start + typesList.length(); typeNum = mm.connectiveArr[connNum].argtypes[i]; // Override the type of the first return char (could be // a variable with type not yet known) typesList = typesList + String.valueOf((char)typeNum) + (new String(getTypes(formula, position))).substring(1); } return typesList; } } // getTypes // Return formula in standard (display) notation // If raw, then each variable is in the form $n:m, where m is the type static String typesList; static final String getDisplay(String formula, boolean raw) { typesList = getTypes(formula, 0); return subGetDisplay(formula, 0, raw); } static final String subGetDisplay(String formula, int start, boolean raw) { // String tokenSeparator = " "; // Separator character between tokens in axiom menu String tokenSeparator = ""; // Separator character between tokens in axiom menu String subformula; int position; short connNum; int i; String[] displayArgs; String displayFormula; String tmpNotation; String token; short argNum; int charPosition0; int charPosition; if (raw) { tokenSeparator = " "; // Must always be a space for further parsing } else { tokenSeparator = ""; // Separator character between tokens in axiom menu } if ((short)(formula.charAt(start)) > 0) { // It's a variable if (raw) { return "$" + Integer.toString((int)formula.charAt(start)) + ":" + Integer.toString((int)typesList.charAt(start)); } else { return VariableName.name((short)(formula.charAt(start)), (short)typesList.charAt(start)); } } else { // It's a connective connNum = (short)(formula.charAt(start)); connNum = (short)(- (connNum + 1)); subformula = formula.substring(start, start + 1); position = start; displayArgs = new String[mm.connectiveArr[connNum].argtypes.length]; // Collect the arguments in display notation for (i = 0; i < mm.connectiveArr[connNum].argtypes.length; i++) { position = start + subformula.length(); subformula = subformula + pformula(formula, position); displayArgs[i] = subGetDisplay(formula, position, raw); } tmpNotation = mm.connectiveArr[connNum].notation + " "; displayFormula = ""; // Replace the arguments in the connectives display notation charPosition0 = 0; charPosition = tmpNotation.indexOf(' '); while (charPosition != -1) { token = tmpNotation.substring(charPosition0, charPosition); if (token.charAt(0) == '$') { // Display template argument argNum = (short)Integer.parseInt(token.substring(1)); if (displayFormula.length() == 0) { displayFormula = displayArgs[argNum - 1]; } else { displayFormula = displayFormula + tokenSeparator + displayArgs[argNum - 1]; } } else { // Display connective - output as is if (displayFormula.length() == 0) { displayFormula = token; } else { displayFormula = displayFormula + tokenSeparator + token; } } charPosition0 = charPosition + 1; charPosition = tmpNotation.indexOf(' ', charPosition0); } return displayFormula; } } // subGetDisplay } // class PrimFormula // Get name for display of variable final class VariableName { static Vector varNameVec = new Vector(); static Vector varTypeVec = new Vector(); static int[] varSoFar = new int[4]; // Counter for how many so far for // each type // Initialize (e.g. after renormalizing variables) final static void init() { varNameVec = new Vector(); varTypeVec = new Vector(); varSoFar = new int[4]; // Initialized to 0; there are 4 types } // Get name of variable - type must be 0 thru 3 (wff thru digit) final static String name(short var, short type) { int v; int quotient; int remainder; String suffix; // wff, var, class, digit String[] letters = {"PQRSTUWXYZ", "xyzwvutsrqpnmlkjihgfdcba", "ABCDFGHJKLMN", "e"}; if (var >= varNameVec.size()) { // extend to accomodate variable varNameVec.setSize((int)(var + 1)); varTypeVec.setSize((int)(var + 1)); } if (varNameVec.elementAt((int)var) == null) { // hasn't been assigned yet // Get name based on type and previous names v = varSoFar[type]; varSoFar[type]++; quotient = v / letters[type].length(); remainder = v % letters[type].length(); if (quotient == 0) { suffix = ""; } else { suffix = Integer.toString((int)(quotient - 1)); } varNameVec.setElementAt( letters[type].substring(remainder, remainder + 1) + suffix, (int)var); varTypeVec.setElementAt(new Integer((int)type), (int)var); } return (String)varNameVec.elementAt((int)var); } // This is a handy way to find out variable's type, but should only // be used after getting the variable's name final static short type(short var) { return (short)(((Integer)(varTypeVec.elementAt((int)var))).intValue()); } } // VariableDisplay // Define a logical connective class Connective { String label; short type; short[] argtypes; String notation; Connective(String label, String wtype, int numArgs, String notation) { this.label = label; this.type = getExprType(wtype); this.argtypes = new short[numArgs]; this.notation = notation; } void setArgtype(int arg, String sarg) { this.argtypes[arg] = getExprType(sarg); } // Get expression type number for input string; return -1 if bad private static short getExprType(String stype) { String TYPE_LIST[] = {"wff", "var", "class", "digit"}; for (int i = 0; i < TYPE_LIST.length; i++) { if (TYPE_LIST[i].equals(stype)) return (short)i; } return (short)(-1); } } // class Connective // Define an axiom // (Future: make Axiom same class as State for uniformity & to simplify pgm?) class Axiom { String label; String assertion; Vector axiomHypothesisVec; Vector axiomDistVarVec; // Each string always has length 2 String proof; // when converted from currentState String description; String menuEntry; // String to put into menu when no unification is // needed (store instead of recompute to speed up menu build) Axiom(String label, String englRPN, String description) { // This is the constructor for built-in axioms this.label = label; this.assertion = englToNumStr(englRPN); this.axiomHypothesisVec = new Vector(); this.axiomDistVarVec = new Vector(); this.description = description; this.proof = ""; // no proof for axiom (user-added theorems have proofs) makeMenuEntry(); } void addHyp(String hyp) { this.axiomHypothesisVec.addElement(englToNumStr(hyp)); } void addDistinct(String distinctVarPair) { this.axiomDistVarVec.addElement(englToNumStr(distinctVarPair)); // Future error check: string length == 2 } // This constructor converts the top of the assertion stack into a Axiom // (Future major revision: make Axiom and State the same class for // simplicity?) Axiom(State st) { // We have to make clones because state contents will be changing State stCopy = st.makeClone(); // Remove all assertions except last Vector trimmedAssertionVec = new Vector(); Vector trimmedProofVec = new Vector(); trimmedAssertionVec.addElement(stCopy.assertionVec.lastElement()); trimmedProofVec.addElement(stCopy.proofVec.lastElement()); stCopy.assertionVec = trimmedAssertionVec; stCopy.proofVec = trimmedProofVec; stCopy.normalize(); // Trim distinct vars this.label = "user-" + String.valueOf(mm.userTheorems.size() + 1); this.assertion = (String)(stCopy.assertionVec.lastElement()); this.proof = (String)(stCopy.proofVec.lastElement()); this.axiomHypothesisVec = stCopy.hypothesisVec; this.axiomDistVarVec = stCopy.distinctVarVec; this.description = "Theorem added by user"; makeMenuEntry(); } private void makeMenuEntry() { // Make string for axiom menu when no unification required VariableName.init(); // Reset variable vs. variable name & type // for PrimFormula.getDisplay(..) menuEntry = String.valueOf( 1 - axiomHypothesisVec.size()) // Amt stack increases + " " + label + " " // Label + PrimFormula.getDisplay(assertion, false); // ASCII formula if (menuEntry.length() > mm.MAX_AXIOM_CHOICE_LEN) { // Trim to size menuEntry = menuEntry.substring(0, mm.MAX_AXIOM_CHOICE_LEN - 3) + "..."; } } // Convert RPN character, space-separated strings to RPN numeric strings // Connectives are negative, variables are positive private static final String englToNumStr(String englRPN) { String token; int position0; int position; short varNum; short connNum; int i; StringBuffer numRPNbuf = new StringBuffer(); englRPN = englRPN + " "; numRPNbuf.ensureCapacity(englRPN.length() / 2); position0 = 0; position = englRPN.indexOf(' '); while (position != -1) { token = englRPN.substring(position0, position); if (token.charAt(0) == '$') { // Variable varNum = (short)Integer.parseInt(token.substring(1)); numRPNbuf.append(String.valueOf((char)varNum)); } else { // Connective i = mm.connectiveLabels.indexOf(" " + token + " "); if (i == -1) System.out.println("Bug: Unknown connective " + token); connNum = (short)(mm.connectiveLabelMap.charAt(i)); numRPNbuf.append(String.valueOf((char)(-(connNum + 1)))); } position0 = position + 1; position = englRPN.indexOf(' ', position0); } return numRPNbuf.toString(); } // englToNumStr } // class Axiom // Define the stack (state) class State { short maxVar; /* Largest variable used */ Vector assertionVec; Vector proofVec; // Proof for each assertion Vector hypothesisVec; Vector distinctVarVec; // each string always has length 2 Vector userThVec; // copy of userTheorems; used for Undo int currentFam; // for Undo State() { // Constructor maxVar = 0; assertionVec = new Vector(); proofVec = new Vector(); hypothesisVec = new Vector(); distinctVarVec = new Vector(); userThVec = mm.userTheorems; currentFam = mm.currentFamily; } State makeClone() { State c = new State(); c.maxVar = this.maxVar; c.assertionVec = (Vector)(this.assertionVec.clone()); c.proofVec = (Vector)(this.proofVec.clone()); c.hypothesisVec = (Vector)(this.hypothesisVec.clone()); c.distinctVarVec = (Vector)(this.distinctVarVec.clone()); c.userThVec = (Vector)(this.userThVec.clone()); return c; } String getAssertion(int position) { return (String)(assertionVec.elementAt(position));} String getStackTop() { return (String)(assertionVec.lastElement());} void pushAssertion(String assertion, String proof) { assertionVec.addElement(assertion); proofVec.addElement(proof); } void removeAssertionAt(int position) {assertionVec.removeElementAt(position);} String getHyp(int position) { return (String)(hypothesisVec.elementAt(position));} void addHyp() { maxVar++; hypothesisVec.addElement(String.valueOf((char)maxVar)); } void removeHypAt(int position) {hypothesisVec.removeElementAt(position);} void normalize() { // Renumber all variables; reduce maxVar if gaps were eliminated // Also, trim off any distinct pairs that aren't in assertion or hyp // (important, otherwise distinct var list will have garbage entries) // Note: variables are numbered starting at 1, not 0. short newMax = 0; short[] varMap = new short[maxVar + 1]; StringBuffer scanBuf; int i; int j; short c; // Scan assertions for (i = 0; i < assertionVec.size(); i++) { scanBuf = new StringBuffer((String)(assertionVec.elementAt(i))); for (j = 0; j < scanBuf.length(); j++) { c = (short)(scanBuf.charAt(j)); if (c < 0) continue; // not a variable if (varMap[c] == 0) { // Add new variable newMax++; varMap[c] = newMax; } scanBuf.setCharAt(j, (char)(varMap[c])); } assertionVec.setElementAt(scanBuf.toString(), i); } // Scan hypotheses for (i = 0; i < hypothesisVec.size(); i++) { scanBuf = new StringBuffer((String)(hypothesisVec.elementAt(i))); for (j = 0; j < scanBuf.length(); j++) { c = (short)(scanBuf.charAt(j)); if (c < 0) continue; // not a variable if (varMap[c] == 0) { // Add new variable newMax++; varMap[c] = newMax; } scanBuf.setCharAt(j, (char)(varMap[c])); } hypothesisVec.setElementAt(scanBuf.toString(), i); } // Scan distinct variable pairs boolean discardFlag; for (i = 0; i < distinctVarVec.size(); i++) { scanBuf = new StringBuffer((String)(distinctVarVec.elementAt(i))); discardFlag = false; for (j = 0; j < scanBuf.length(); j++) { if (j > 1) System.out.println("Bug #1"); // S.b. only two vars each c = (short)(scanBuf.charAt(j)); if (varMap[c] == 0) { // In the case of distinct variables, we want to throw away // ones not yet mapped (i.e. in no assertion or hypothesis) discardFlag = true; break; } scanBuf.setCharAt(j, (char)(varMap[c])); } if (!discardFlag) { distinctVarVec.setElementAt(scanBuf.toString(), i); } else { distinctVarVec.removeElementAt(i); i--; } } // Update maxVar maxVar = newMax; // Initialize variable name/type finder VariableName.init(); } // Build a special version of a State containing all steps of the proof // instead of just the stack entries. Also, each proofVec string in the // special State has instead of an // axiom list. Used to display detailed proof for the 'Proof Info' // option. final static State buildProofInfoState(State currentState) { // Add proof steps one by one with special unify() mode, keeping all steps // Get the axiom-list version of the proof of the top of the stack String proof = (String)(currentState.proofVec.lastElement()); State proofInfoState = new State(); // Copy any hypotheses for (int i = 0; i < currentState.hypothesisVec.size(); i++) { proofInfoState.addHyp(); } // Scan the axiom-list proof proof = proof + " "; int position0 = 0; int position = proof.indexOf(' '); String label; while (position != -1) { label = proof.substring(position0, position); if (label.charAt(0) == '$') { // Hypothesis $hypnn - future: make sure // that $ is not allowed if user name accepted for user proofs int hypNum = Integer.parseInt(label.substring(4)) - 1; proofInfoState.pushAssertion( (String)(proofInfoState.hypothesisVec.elementAt(hypNum)), // Special label for hypothesis step String.valueOf(proofInfoState.assertionVec.size() + 1) + " " + label); } else { // Find the axiom with this label // Linear seach -- future speedup? int i; for (i = 0; i < mm.axiomArr.length; i++) { if (mm.axiomArr[i] == null) continue; if (mm.axiomArr[i].label.equals(label)) break; } proofInfoState = Unification.unify(mm.axiomArr[i], proofInfoState, true); // true means unification will not delete popped hypotheses } position0 = position + 1; position = proof.indexOf(' ', position0); } // end while position != -1 // Sort the proof steps (they are not sorted in proofInfoState) int[] stepSortMap = new int[proofInfoState.assertionVec.size()]; for (int i = 0; i < stepSortMap.length; i++) { String labl = (String)(proofInfoState.proofVec.elementAt(i)); int stepNum = Integer.parseInt(labl.substring(0, labl.indexOf(' '))) - 1; stepSortMap[stepNum] = i; } Vector sortedAssertionVec = new Vector(); Vector sortedProofVec = new Vector(); for (int i = 0; i < stepSortMap.length; i++) { int step = stepSortMap[i]; sortedAssertionVec.addElement(proofInfoState.assertionVec.elementAt(step)); sortedProofVec.addElement(proofInfoState.proofVec.elementAt(step)); } proofInfoState.assertionVec = sortedAssertionVec; proofInfoState.proofVec = sortedProofVec; // end sort proofInfoState.normalize(); // Trim distinct vars, init var names // Dummy run thru steps in reverse order for desired variable name // assignment for (int i = proofInfoState.assertionVec.size() - 1; i >=0; i--) { String dummy = PrimFormula.getDisplay( (String)(proofInfoState.assertionVec.elementAt(i)), false); } return proofInfoState; } // buildProofInfoState } // class State // Define a substitution class Substitution { short substVar; // The variable being substituted String substString; // What it's substituted with Substitution(short substVar, String substString) { this.substVar = substVar; this.substString = substString; } // Makes a substitution into a formula final static String makeSubst(String formula, Substitution subst) { int i; i = -1; while (true) { i = formula.indexOf((int)subst.substVar, i + 1); if (i < 0) break; formula = formula.substring(0, i) + subst.substString + formula.substring(i + 1); } return formula; } // Makes a set of substitutions into a formula final static String makeVecSubst(String formula, Vector substVec) { int i; for (i = 0; i < substVec.size(); i++) { formula = makeSubst(formula, (Substitution)(substVec.elementAt(i))); } return formula; } } // class Substitution // Define unification methods final class Unification { // These variables are used by calling program static Vector newDistinctVarVec; static short oldMaxVar; // Original largest variable static short newMaxVar; // New largest variable static Vector substVec; // Substitution list to make throughout State // Local static variables static Vector axiomHypVec = new Vector(); static Vector stateHypVec = new Vector(); // Unification algorithm - returns a new State if unification // possible, null otherwise final static State unify(Axiom testAxiom, State currentState, boolean proofInfoFlag) { int i; short newVar; int hyp; short cr; short cs; short substVar; String substStr; Substitution subst; int currentStateStackSize; int axiomHypSize; State newState; String axiomHyp; String stateHyp; substVec = new Vector(); currentStateStackSize = currentState.assertionVec.size(); if (testAxiom == null) return null; // To allow for sloppy axiom array axiomHypSize = testAxiom.axiomHypothesisVec.size(); // See if stack has enough entries if (currentStateStackSize < axiomHypSize) { return null; } // Build state hypothesis vector stateHypVec = new Vector(); for (hyp = 0; hyp < axiomHypSize; hyp++) { stateHypVec.addElement(currentState.assertionVec.elementAt( currentStateStackSize - axiomHypSize + hyp)); } // Don't destroy caller's distinctVarVec newDistinctVarVec = (Vector)(currentState.distinctVarVec.clone()); oldMaxVar = currentState.maxVar; newMaxVar = currentState.maxVar; // Build axiom hypothesis vector with renumbered variables axiomHypVec = new Vector(); for (hyp = 0; hyp < axiomHypSize; hyp++) { axiomHypVec.addElement(renumberVars((String) (testAxiom.axiomHypothesisVec.elementAt(hyp)))); } // Renumber distinct variables of axiom and add to dist var vector for (i = 0; i < testAxiom.axiomDistVarVec.size(); i++) { newDistinctVarVec.addElement(renumberVars((String)( testAxiom.axiomDistVarVec.elementAt(i)))); } // Unify each hypothesis for (hyp = 0; hyp < axiomHypSize; hyp++) { i = -1; while (true) { i++; // Assign working hypotheses strings; also reassign them each // pass thru loop to reflect result of substitution at end of loop axiomHyp = (String)(axiomHypVec.elementAt(hyp)); stateHyp = (String)(stateHypVec.elementAt(hyp)); if (i >= axiomHyp.length() || i >= stateHyp.length()) { break; } cr = (short)(axiomHyp.charAt(i)); cs = (short)(stateHyp.charAt(i)); if (cr == cs) continue; if (cr > 0) { // Variable in axiom substStr = PrimFormula.pformula(stateHyp, i); // Get subformula substVar = cr; } else { if (cs > 0) { // Variable in state hyp substStr = PrimFormula.pformula(axiomHyp, i); // Get subformula substVar = cs; } else { return null; // Unif not possible - connectives mismatch } } if (substStr.indexOf((char)substVar) >= 0) { return null; // Unif not possible - substituted var in substitution } subst = new Substitution(substVar, substStr); if (!rebuildDistinct(subst)) { return null; // Dist var violation } makeSub(subst); // Make subst to hyp's and substVec substVec.addElement(subst); } if (axiomHyp.length() != stateHyp.length()) { return null; // Unif not possible } } // Build new State to return to caller newState = new State(); // Build new assertion stack newState.assertionVec = new Vector(); if (proofInfoFlag) { // Don't discard used-up assertions in this mode, but put them // at the bottom of the stack so they'll be available for the detailed // proof for (i = currentStateStackSize - axiomHypSize; i < currentStateStackSize; i++) { newState.pushAssertion(Substitution.makeVecSubst( (String)(currentState.assertionVec.elementAt(i)), substVec), (String)(currentState.proofVec.elementAt(i))); } } // Copy assertions and their proofs that were not popped by unification for (i = 0; i < currentStateStackSize - axiomHypSize; i++) { newState.pushAssertion(Substitution.makeVecSubst( (String)(currentState.assertionVec.elementAt(i)), substVec), (String)(currentState.proofVec.elementAt(i))); } // Build proof for new assertion String newProof = testAxiom.label; if (proofInfoFlag) { // Format is step#, axiom used, steps used by hypotheses of axiom newProof = String.valueOf(currentStateStackSize + 1) + " " + newProof; //for (i = currentStateStackSize - axiomHypSize; i < currentStateStackSize; // i++) { for (i = currentStateStackSize - 1; i >= currentStateStackSize - axiomHypSize; i--) { newProof = newProof + "," + ((String)(currentState.proofVec.elementAt(i))).substring(0, ((String)(currentState.proofVec.elementAt(i))).indexOf(' ')); } } else { // Format is axiom used, preceded by concatenated proofs of hypotheses for (i = currentStateStackSize - 1; i >= currentStateStackSize - axiomHypSize; i--) { newProof = (String)(currentState.proofVec.elementAt(i)) + " " + newProof; } } // Push new, substituted assertion and proof from result of axiom newState.pushAssertion( Substitution.makeVecSubst(renumberVars(testAxiom.assertion), substVec), newProof); // Copy hypotheses with substitutions made to them for (i = 0; i < currentState.hypothesisVec.size(); i++) { newState.hypothesisVec.addElement(Substitution.makeVecSubst( (String)(currentState.hypothesisVec.elementAt(i)), substVec)); } // Assign distinct variable list newState.distinctVarVec = newDistinctVarVec; // Assign largest variable newState.maxVar = newMaxVar; return newState; } // Renumber variables in a formula from a axiom, by adding axiom's var # // (which must be > 0) to oldMaxVar final static String renumberVars(String axiomFormula) { StringBuffer formulaBuf = new StringBuffer(axiomFormula); int i; short newVar; // Renumber variables for (i = 0; i < formulaBuf.length(); i++) { if ((short)(formulaBuf.charAt(i)) > 0) { newVar = (short)(oldMaxVar + (short)(formulaBuf.charAt(i))); formulaBuf.setCharAt(i, (char)newVar); if (newVar > newMaxVar) newMaxVar = newVar; } } return formulaBuf.toString(); } // Make substitution to hyp's and substVec (substVec is theoretically // not necessary but done to speed things up) final static void makeSub(Substitution subst) { int hyp; int sub; int i; for (hyp = 0; hyp < stateHypVec.size(); hyp++) { stateHypVec.setElementAt( Substitution.makeSubst((String)(stateHypVec.elementAt(hyp)), subst), hyp); axiomHypVec.setElementAt( Substitution.makeSubst((String)(axiomHypVec.elementAt(hyp)), subst), hyp); } for (sub = 0; sub < substVec.size(); sub++) { ((Substitution)(substVec.elementAt(sub))).substString = Substitution.makeSubst( ((Substitution)(substVec.elementAt(sub))).substString, subst); } } // Rebuild newDistinctVarVec after a substitution // Returns true if no distinct variable violations, false if there were final static boolean rebuildDistinct(Substitution subst) { int ilimit = newDistinctVarVec.size(); int i; int j; boolean found = false; short v0; short v1; short vsub; String dpair; for (i = 0; i < ilimit; i++) { v0 = (short)(((String)(newDistinctVarVec.elementAt(i))).charAt(0)); v1 = (short)(((String)(newDistinctVarVec.elementAt(i))).charAt(1)); if (v1 == subst.substVar) { short vtmp = v0; v0 = v1; v1 = vtmp; } if (v0 == subst.substVar) { // 1st var is substituted for (j = 0; j < (subst.substString).length(); j++) { vsub = (short)((subst.substString).charAt(j)); if (vsub < 0) continue; // Not a variable if (vsub == v1) { // Distinct variable conflict return false; } // Spawn off a new pair dpair = String.valueOf((char)vsub) + String.valueOf((char)v1); newDistinctVarVec.addElement(dpair); } // Remove substituted pair newDistinctVarVec.removeElementAt(i); // And lower limits i--; ilimit--; found = true; } } if (found) { // If a substitution was made, clean up the list // Put variables in ascending order in each pair ilimit = newDistinctVarVec.size(); for (i = 0; i < ilimit; i++) { v0 = (short)(((String)(newDistinctVarVec.elementAt(i))).charAt(0)); v1 = (short)(((String)(newDistinctVarVec.elementAt(i))).charAt(1)); if (v0 > v1) { // Swap vars dpair = String.valueOf((char)v1) + String.valueOf((char)v0); newDistinctVarVec.setElementAt(dpair, i); } } // Sort the list QSort.sort(newDistinctVarVec); // Remove duplicates for (i = ilimit - 1; i > 0; i--) { if (((String)(newDistinctVarVec.elementAt(i))).equals( ((String)(newDistinctVarVec.elementAt(i - 1))))) { // Remove one of them newDistinctVarVec.removeElementAt(i); } } } return true; } // rebuildDistinct } final class QSort { // Source: Darin Warling static final public void sort(Vector v) { // Sort the whole array: sort(v, 0, v.size() - 1); } static final private void sort(Vector v, int l, int r) { // If we haven't reached a termination condition... if ( l < r ) { // Partition the vector into left and right halves: int p = partition(v, l, r); // Recursively sort each half: sort(v, l, p); sort(v, p+1, r); } } static final private int partition(Vector v, int l, int r) { // Arbitrarily pick the left element as the pivot element: String s = v.elementAt(l).toString(); l--; r++; while (true) { // Figure out what's smaller and what's larger than the pivot: while (v.elementAt(--r).toString().compareTo(s) > 0) ; while (v.elementAt(++l).toString().compareTo(s) < 0) ; // Swap elements if we can: if (l < r) { Object o = v.elementAt(l); v.setElementAt(v.elementAt(r), l); v.setElementAt(o, r); } else return r; } } } // class QSort