diff --git a/PropositionalLogic.ipynb b/PropositionalLogic.ipynb index 5a3cf51..b35efb0 100644 --- a/PropositionalLogic.ipynb +++ b/PropositionalLogic.ipynb @@ -32,9 +32,11 @@ " \n", "which means that the logic translation will have the form `'P ⇒ Q'`, whenever the English sentence has either the form `'if P then Q'` or `'if P, Q'`, where `P` and `Q` can match any non-empty subsequence of characters. Whatever matches `P` and `Q` will be recursively processed by the rules. The rules are in order—top to bottom, left to right, and the first rule that matches in that order will be accepted, no matter what, so be sure you order your rules carefully. One guideline I have adhered to is to put all the rules that start with a keyword (like `'if'` or `'neither'`) before the rules that start with a variable (like `'{P}'`); that way you avoid accidently having a keyword swallowed up inside a `'{P}'`.\n", "\n", - "Notice that given the sentence \"*Sieglinde will survive*\", the program should make up a new propositional symbol, `P`, and record the fact that `P` refers to \"*Sieglinde will survive*\". But the negative sentence \"*Sieglinde will not survive*\", should be translated as `~P`, where again `P` is \"*Sieglinde will survive*\". So to fully specify the translation process, we need to define both `rules` and `negations`. (We do that using [regular expressions](https://docs.python.org/3.5/library/re.html), which can sometimes be confusing.)\n", + "Consider the example sentence `\"If loving you is wrong, I don't want to be right.\"` This should match the pattern \n", + "`'if {P}, {Q}'` with the variable `P` equal to `\"loving you is wrong\"`. But I don't want the variable `Q` to be \n", + "`\"I don't want to be right\"`, rather, I want to have `~Q` equal to `\"I do want to be right\"`. So in addition to having a set of `Rule`s to handle the `'if {P}, {Q}'` patterns, I will also have a list of `negations` to handle `\"don't\"` and the like.\n", "\n", - "First the function to define a rule (and some auxiliary functions):" + "Here is the code to process `Rule` definitions (using [regular expressions](https://docs.python.org/3.5/library/re.html), which can sometimes be confusing.)." ] }, { @@ -90,7 +92,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "And now the actual rules. If you have a sentence that is not translated correctly by this program, you can augment these rules to handle your sentence." + "And now the actual rules. If your sentence is not translated correctly, you can attempt to augment these rules to handle your sentence." ] }, { @@ -127,7 +129,8 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Now the mechanism to process these rules. Note that the parameter `defs` is a dict of definitions of propositional symbols: `{P: 'english'}`. The three `match_*` functions return two values: the translation of a sentence, and a dict of defintions." + "Now the mechanism to process these rules. The key function is `match_rule`, which matches an English sentence against a rule. The function returns two values, a string representing the translation of the Eng;lish sentence into logic, and `defs`, a dictionary of `{Variable: \"value\"}` pairs. If `match_rule` finds that the rule matches, it recursively calls `match_rules` to match each of the subgroups of the regular expression (the `P` and `Q` in `if {P}, then {Q}`).\n", + "The function `match_literal` handles negations, and is where the `defs` dictionary actually gets updated." ] }, { @@ -137,17 +140,17 @@ "outputs": [], "source": [ "def match_rules(sentence, rules, defs):\n", - " \"\"\"Match sentence against all the rules, accepting the first match; or else make it an atomic proposition.\n", + " \"\"\"Match sentence against all the rules, accepting the first match; or else make it an atom.\n", " Return two values: the Logic translation and a dict of {P: 'english'} definitions.\"\"\"\n", " sentence = clean(sentence)\n", " for rule in rules:\n", " result = match_rule(sentence, rule, defs)\n", " if result: \n", " return result\n", - " return match_atomic_proposition(sentence, negations, defs)\n", + " return match_literal(sentence, negations, defs)\n", " \n", "def match_rule(sentence, rule, defs):\n", - " \"Match a single rule, returning the logic translation and the dict of definitions if the match succeeds.\"\n", + " \"Match rule, returning the logic translation and the dict of definitions if the match succeeds.\"\n", " output, patterns = rule\n", " for pat in patterns:\n", " match = re.match(pat, sentence, flags=re.I)\n", @@ -157,7 +160,7 @@ " groups[P] = match_rules(groups[P], rules, defs)[0]\n", " return '(' + output.format(**groups) + ')', defs\n", " \n", - "def match_atomic_proposition(sentence, negations, defs):\n", + "def match_literal(sentence, negations, defs):\n", " \"No rule matched; sentence is an atom. Add new proposition to defs. Handle negation.\"\n", " polarity = ''\n", " for (neg, pos) in negations:\n", @@ -185,120 +188,171 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "And finally some test sentences and a top-level function to produce output:" + "For example:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "('(P ⇒ ~Q)', {'P': 'loving you is wrong', 'Q': 'I do want to be right'})" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "match_rule(\"If loving you is wrong, I don't want to be right\",\n", + " Rule('{P} ⇒ {Q}', 'if {P}, {Q}'),\n", + " {})" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here are some more test sentences and a top-level function to handle them:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "__________________________________________________________________________________________ \n", - "Polkadots and Moonbeams \n", + "\n", + "English: Polkadots and Moonbeams. \n", + "\n", "Logic: (P ⋀ Q)\n", "P: Polkadots\n", "Q: Moonbeams\n", - "__________________________________________________________________________________________ \n", - "If you liked it then you shoulda put a ring on it \n", + "\n", + "English: If you liked it then you shoulda put a ring on it. \n", + "\n", "Logic: (P ⇒ Q)\n", "P: you liked it\n", "Q: you shoulda put a ring on it\n", - "__________________________________________________________________________________________ \n", - "If you build it, he will come \n", + "\n", + "English: If you build it, he will come. \n", + "\n", "Logic: (P ⇒ Q)\n", "P: you build it\n", "Q: he will come\n", - "__________________________________________________________________________________________ \n", - "It don't mean a thing, if it ain't got that swing \n", + "\n", + "English: It don't mean a thing, if it ain't got that swing. \n", + "\n", "Logic: (~P ⇒ ~Q)\n", "P: it is got that swing\n", "Q: It do mean a thing\n", - "__________________________________________________________________________________________ \n", - "If loving you is wrong, I don't want to be right \n", + "\n", + "English: If loving you is wrong, I don't want to be right. \n", + "\n", "Logic: (P ⇒ ~Q)\n", "P: loving you is wrong\n", "Q: I do want to be right\n", - "__________________________________________________________________________________________ \n", - "Should I stay or should I go \n", + "\n", + "English: Should I stay or should I go. \n", + "\n", "Logic: (P ⋁ Q)\n", "P: Should I stay\n", "Q: should I go\n", - "__________________________________________________________________________________________ \n", - "I shouldn't go and I shouldn't not go \n", + "\n", + "English: I shouldn't go and I shouldn't not go. \n", + "\n", "Logic: (~P ⋀ ~~P)\n", "P: I should go\n", - "__________________________________________________________________________________________ \n", - "If I fell in love with you, would you promise to be true and help me understand \n", + "\n", + "English: If I fell in love with you, would you promise to be true and help me\n", + "understand. \n", + "\n", "Logic: (P ⇒ (Q ⋀ R))\n", "P: I fell in love with you\n", "Q: would you promise to be true\n", "R: help me understand\n", - "__________________________________________________________________________________________ \n", - "I could while away the hours conferrin' with the flowers, consulting with the rain and my\n", - "head I'd be a scratchin' while my thoughts are busy hatchin' if I only had a brain \n", + "\n", + "English: I could while away the hours conferrin' with the flowers, consulting\n", + "with the rain and my head I'd be a scratchin' while my thoughts are busy\n", + "hatchin' if I only had a brain. \n", + "\n", "Logic: (P ⇒ (Q ⋀ R))\n", "P: I only had a brain\n", "Q: I could while away the hours conferrin' with the flowers, consulting with the rain\n", "R: my head I'd be a scratchin' while my thoughts are busy hatchin'\n", - "__________________________________________________________________________________________ \n", - "There's a federal tax, and a state tax, and a city tax, and a street tax, and a sewer tax \n", + "\n", + "English: There's a federal tax, and a state tax, and a city tax, and a street\n", + "tax, and a sewer tax. \n", + "\n", "Logic: (P ⋀ (Q ⋀ (R ⋀ (S ⋀ T))))\n", "P: There's a federal tax\n", "Q: a state tax\n", "R: a city tax\n", "S: a street tax\n", "T: a sewer tax\n", - "__________________________________________________________________________________________ \n", - "A ham sandwich is better than nothing and nothing is better than eternal happiness\n", - "therefore a ham sandwich is better than eternal happiness \n", + "\n", + "English: A ham sandwich is better than nothing and nothing is better than\n", + "eternal happiness therefore a ham sandwich is better than eternal happiness. \n", + "\n", "Logic: ((P ⋀ Q) ⇒ R)\n", "P: A ham sandwich is better than nothing\n", "Q: nothing is better than eternal happiness\n", "R: a ham sandwich is better than eternal happiness\n", - "__________________________________________________________________________________________ \n", - "If I were a carpenter and you were a lady, would you marry me anyway? and would you have\n", - "my baby \n", + "\n", + "English: If I were a carpenter and you were a lady, would you marry me anyway?\n", + "and would you have my baby. \n", + "\n", "Logic: ((P ⋀ Q) ⇒ (R ⋀ S))\n", "P: I were a carpenter\n", "Q: you were a lady\n", "R: would you marry me anyway?\n", "S: would you have my baby\n", - "__________________________________________________________________________________________ \n", - "Either Danny didn't come to the party or Virgil didn't come to the party \n", + "\n", + "English: Either Danny didn't come to the party or Virgil didn't come to the\n", + "party. \n", + "\n", "Logic: (~P ⋁ ~Q)\n", "P: Danny did come to the party\n", "Q: Virgil did come to the party\n", - "__________________________________________________________________________________________ \n", - "Either Wotan will triumph and Valhalla will be saved or else he won't and Alberic will\n", - "have the final word \n", + "\n", + "English: Either Wotan will triumph and Valhalla will be saved or else he won't\n", + "and Alberic will have the final word. \n", + "\n", "Logic: ((P ⋀ Q) ⋁ (~R ⋀ S))\n", "P: Wotan will triumph\n", "Q: Valhalla will be saved\n", "R: he will\n", "S: Alberic will have the final word\n", - "__________________________________________________________________________________________ \n", - "Sieglinde will survive, and either her son will gain the Ring and Wotan's plan will be\n", - "fulfilled or else Valhalla will be destroyed \n", + "\n", + "English: Sieglinde will survive, and either her son will gain the Ring and\n", + "Wotan's plan will be fulfilled or else Valhalla will be destroyed. \n", + "\n", "Logic: (P ⋀ ((Q ⋀ R) ⋁ S))\n", "P: Sieglinde will survive\n", "Q: her son will gain the Ring\n", "R: Wotan's plan will be fulfilled\n", "S: Valhalla will be destroyed\n", - "__________________________________________________________________________________________ \n", - "Wotan will intervene and cause Siegmund's death unless either Fricka relents or Brunnhilde\n", - "has her way \n", + "\n", + "English: Wotan will intervene and cause Siegmund's death unless either Fricka\n", + "relents or Brunnhilde has her way. \n", + "\n", "Logic: (~(R ⋁ S) ⇒ (P ⋀ Q))\n", "P: Wotan will intervene\n", "Q: cause Siegmund's death\n", "R: Fricka relents\n", "S: Brunnhilde has her way\n", - "__________________________________________________________________________________________ \n", - "Figaro and Susanna will wed provided that either Antonio or Figaro pays and Bartolo is\n", - "satisfied or else Marcellina's contract is voided and the Countess does not act rashly \n", + "\n", + "English: Figaro and Susanna will wed provided that either Antonio or Figaro pays\n", + "and Bartolo is satisfied or else Marcellina's contract is voided and the\n", + "Countess does not act rashly. \n", + "\n", "Logic: ((((P ⋁ Q) ⋀ R) ⋁ (S ⋀ ~T)) ⇒ (U ⋀ V))\n", "P: Antonio\n", "Q: Figaro pays\n", @@ -307,10 +361,11 @@ "T: the Countess does act rashly\n", "U: Figaro\n", "V: Susanna will wed\n", - "__________________________________________________________________________________________ \n", - "If the Kaiser neither prevents Bismarck from resigning nor supports the Liberals, then the\n", - "military will be in control and either Moltke's plan will be executed or else the people\n", - "will revolt and the Reich will not survive \n", + "\n", + "English: If the Kaiser neither prevents Bismarck from resigning nor supports the\n", + "Liberals, then the military will be in control and either Moltke's plan will be\n", + "executed or else the people will revolt and the Reich will not survive. \n", + "\n", "Logic: ((~PQ ⋀ ~PR) ⇒ (S ⋀ (T ⋁ (U ⋀ ~V))))\n", "P: the Kaiser\n", "Q: prevents Bismarck from resigning\n", @@ -349,10 +404,12 @@ " would you marry me anyway?\n", " and would you have my baby.\n", "Either Danny didn't come to the party or Virgil didn't come to the party.\n", - "Either Wotan will triumph and Valhalla will be saved or else he won't and Alberic will have the final word.\n", - "Sieglinde will survive, and either her son will gain the Ring and Wotan’s plan will be fulfilled \n", - " or else Valhalla will be destroyed.\n", - "Wotan will intervene and cause Siegmund's death unless either Fricka relents or Brunnhilde has her way.\n", + "Either Wotan will triumph and Valhalla will be saved or else he won't and Alberic will have \n", + " the final word.\n", + "Sieglinde will survive, and either her son will gain the Ring and Wotan’s plan \n", + " will be fulfilled or else Valhalla will be destroyed.\n", + "Wotan will intervene and cause Siegmund's death unless either Fricka relents \n", + " or Brunnhilde has her way.\n", "Figaro and Susanna will wed provided that either Antonio or Figaro pays and Bartolo is satisfied \n", " or else Marcellina’s contract is voided and the Countess does not act rashly.\n", "If the Kaiser neither prevents Bismarck from resigning nor supports the Liberals, \n", @@ -361,11 +418,11 @@ "\n", "import textwrap\n", "\n", - "def logic(sentences, width=90): \n", + "def logic(sentences, width=80): \n", " \"Match the rules against each sentence in text, and print each result.\"\n", " for s in map(clean, sentences):\n", " logic, defs = match_rules(s, rules, {})\n", - " print(width*'_', '\\n' + textwrap.fill(s, width), '\\nLogic:', logic)\n", + " print('\\n' + textwrap.fill('English: ' + s +'.', width), '\\n\\nLogic:', logic)\n", " for P in sorted(defs):\n", " print('{}: {}'.format(P, defs[P]))\n", "\n",