Source code for pytableaux.logics.mh

# -*- coding: utf-8 -*-
# pytableaux, a multi-logic proof generator.
# Copyright (C) 2014-2023 Doug Owings.
# 
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
# 
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations

from ..lang import Operator
from ..proof import adds, sdnode
from ..tools import group
from . import fde as FDE
from . import k3 as K3
from . import LogicType

class Meta(K3.Meta):
    name = 'MH'
    title = 'Paracomplete Hybrid Logic'
    quantified = False
    description = (
        'Three-valued logic (True, False, Neither) with non-standard disjunction, '
        'and a classical-like conditional')
    category_order = 11
    native_operators = FDE.Meta.native_operators | (
        Operator.Conditional,
        Operator.Biconditional)

class Model(FDE.Model):

    class TruthFunction(K3.Model.TruthFunction):

        def Disjunction(self, a, b):
            if a == self.values.N and b == self.values.N:
                return self.values.F
            return super().Disjunction(a, b)

        def Conditional(self, a, b):
            if a == self.values.T and b != self.values.T:
                return self.values.F
            return self.values.T

class System(FDE.System): pass

[docs] class Rules(LogicType.Rules): closure = K3.Rules.closure
[docs] class DisjunctionNegatedDesignated(System.OperatorNodeRule): """ From an unticked, negated, designated disjunction node *n* on a branch *b*, make two branches *b'* and *b''* from *b*. On *b'* add four undesignated nodes, one for each disjunct and its negation. On *b''* add two designated nodes, one for the negation of each disjunct. Then tick *n*. """ def _get_sd_targets(self, s, d, /): lhs, rhs = s yield adds( group( sdnode( lhs, not d), sdnode(~lhs, not d), sdnode( rhs, not d), sdnode(~rhs, not d)), group( sdnode(~lhs, d), sdnode(~rhs, d)))
[docs] class DisjunctionNegatedUndesignated(System.OperatorNodeRule): """ From an unticked, negated, undesignated disjunction node *n* on a branch *b*, make four branches from *b*: *b'*, *b''*, *b'''*, and *b''''*. On *b'*, add a designated node with the first disjunct, and on *b''*, add a designated node with the second disjunct. On *b'''* add three nodes: - An undesignated node with the first disjunct. - An undesignated node with the negation of the first disjunct. - A designated node with the negation of the second disjunct. On *b''''* add three nodes: - An undesignated node with the second disjunct. - An undesignated node with the negation of the second disjunct. - A designated node with the negation of the first disjunct. Then tick *n*. """ def _get_sd_targets(self, s, d, /): lhs, rhs = s yield adds( group( sdnode(lhs, not d)), group( sdnode(rhs, not d)), group( sdnode(lhs, d), sdnode(~lhs, d), sdnode(~rhs, not d)), group( sdnode(rhs, d), sdnode(~rhs, d), sdnode(~lhs, not d)))
[docs] class MaterialConditionalNegatedDesignated(System.OperatorNodeRule): def _get_sd_targets(self, s, d, /): lhs, rhs = s yield adds( group( sdnode( lhs, not d), sdnode(~lhs, not d), sdnode( rhs, not d), sdnode(~rhs, not d)), group( sdnode(lhs, d), sdnode(~rhs, d)))
[docs] class MaterialConditionalNegatedUndesignated(System.OperatorNodeRule): def _get_sd_targets(self, s, d, /): lhs, rhs = s yield adds( group( sdnode(~lhs, not d)), group( sdnode(rhs, not d)), group( sdnode(lhs, d), sdnode(~lhs, d), sdnode(~rhs, not d)), group( sdnode(rhs, d), sdnode(~rhs, d), sdnode(lhs, not d)))
[docs] class MaterialBiconditionalDesignated(System.MaterialConditionalConjunctsReducingRule): pass
[docs] class MaterialBiconditionalNegatedDesignated(System.MaterialConditionalConjunctsReducingRule): pass
[docs] class MaterialBiconditionalUndesignated(System.MaterialConditionalConjunctsReducingRule): pass
[docs] class MaterialBiconditionalNegatedUndesignated(System.MaterialConditionalConjunctsReducingRule): pass
[docs] class ConditionalDesignated(System.OperatorNodeRule): """ From an unticked, designated conditional node *n* on a branch *b*, make two branches *b'* and *b''* from *b*. On *b'* add an undesignated node with the antecedent, and on *b''* add a designated node with the consequent. Then tick *n*. """ def _get_sd_targets(self, s, d, /): # Keep designation fixed for inheritance below. yield adds( group(sdnode(s.lhs, False)), group(sdnode(s.rhs, True)))
[docs] class ConditionalNegatedDesignated(System.OperatorNodeRule): """ From an unticked, negated, desigated conditional node *n* on a branch *b*, add two nodes to *b*: - A designated node with the antecedent. - An undesignated node with the consequent. Then tick *n*. """ def _get_sd_targets(self, s, d, /): # Keep designation fixed for inheritance below. yield adds(group(sdnode(s.lhs, True), sdnode(s.rhs, False)))
[docs] class ConditionalUndesignated(ConditionalNegatedDesignated): pass
[docs] class ConditionalNegatedUndesignated(ConditionalDesignated): pass
[docs] class BiconditionalDesignated(System.ConditionalConjunctsReducingRule): pass
[docs] class BiconditionalNegatedDesignated(System.ConditionalConjunctsReducingRule): pass
[docs] class BiconditionalUndesignated(System.ConditionalConjunctsReducingRule): pass
[docs] class BiconditionalNegatedUndesignated(System.ConditionalConjunctsReducingRule): pass
groups = ( # Non-branching rules. group( FDE.Rules.AssertionDesignated, FDE.Rules.AssertionUndesignated, FDE.Rules.AssertionNegatedDesignated, FDE.Rules.AssertionNegatedUndesignated, FDE.Rules.ConjunctionDesignated, FDE.Rules.ConjunctionNegatedUndesignated, FDE.Rules.DisjunctionUndesignated, FDE.Rules.MaterialConditionalUndesignated, MaterialBiconditionalDesignated, MaterialBiconditionalNegatedDesignated, MaterialBiconditionalUndesignated, MaterialBiconditionalNegatedUndesignated, ConditionalUndesignated, ConditionalNegatedDesignated, BiconditionalDesignated, BiconditionalNegatedDesignated, BiconditionalUndesignated, BiconditionalNegatedUndesignated, FDE.Rules.DoubleNegationDesignated, FDE.Rules.DoubleNegationUndesignated), # 1-branching rules. group( FDE.Rules.ConjunctionUndesignated, FDE.Rules.ConjunctionNegatedDesignated, FDE.Rules.DisjunctionDesignated, DisjunctionNegatedDesignated, FDE.Rules.MaterialConditionalDesignated, MaterialConditionalNegatedDesignated, ConditionalDesignated, ConditionalNegatedUndesignated), # 3-branching rules. group( MaterialConditionalNegatedUndesignated, DisjunctionNegatedUndesignated)) @classmethod def _check_groups(cls): for branching, group in zip((0, 1, 3), cls.groups): for rulecls in group: assert rulecls.branching == branching, f'{rulecls}'