mvlogics 0.9.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mvlogics/__init__.py +104 -0
- mvlogics/__init__.pyi +186 -0
- mvlogics/base.py +108 -0
- mvlogics/protocols.pyi +89 -0
- mvlogics-0.9.0.dist-info/METADATA +20 -0
- mvlogics-0.9.0.dist-info/RECORD +9 -0
- mvlogics-0.9.0.dist-info/WHEEL +5 -0
- mvlogics-0.9.0.dist-info/licenses/LICENSE +21 -0
- mvlogics-0.9.0.dist-info/top_level.txt +1 -0
mvlogics/__init__.py
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
from .base import Fraction, Decimal, _AllLogicMeta, _FakeProtocolMeta, _DecimalLogicMeta, _RationalLogicMeta, _FastEnumLogicMeta, _SubmoduleMeta, _singleton_new, REQUIRED_ATTRS, FORBIDDEN, ALL_LOGICS, ALL_LOGICS_TUPLE, ALL_METHODS, FAKE_PROTOCOLS, FAKE_PROTOCOLS_TUPLE, RECOMMENDED_METHODS, MIXIN_METHODS, EXTENSION_METHODS, _all as __all__
|
|
2
|
+
def is_logic(typ): return isinstance(typ, _AllLogicMeta)
|
|
3
|
+
def is_logic_member(obj): return is_logic(type(obj))
|
|
4
|
+
def is_builtin_logic(typ): return typ.__name__ in ALL_LOGICS and typ.__module__ == __name__
|
|
5
|
+
def is_builtin_logic_member(obj): return is_builtin_logic(type(obj))
|
|
6
|
+
def convert(member, cls):
|
|
7
|
+
if isinstance(member, type): cls, member = member, cls
|
|
8
|
+
return member.convert_to(cls)
|
|
9
|
+
class Unit(metaclass=_AllLogicMeta):
|
|
10
|
+
__new__ = _singleton_new; box = diamond = __invert__ = lambda self: self; __and__ = __or__ = implies = gullibility = consensus = lambda self, _, /: self
|
|
11
|
+
def __bool__(self): raise TypeError('cannot convert Unit to bool')
|
|
12
|
+
def __repr__(self): return 'Unit.T'
|
|
13
|
+
def normalized(self): return Fraction(1)
|
|
14
|
+
@classmethod
|
|
15
|
+
def from_normalized(cls, val):
|
|
16
|
+
if val == Fraction(1): return cls()
|
|
17
|
+
raise ValueError(f'could not construct instance from val {val}')
|
|
18
|
+
def __reduce__(self): return type(self), ()
|
|
19
|
+
Unit.T = Unit()
|
|
20
|
+
class Boolean(metaclass=_FastEnumLogicMeta):
|
|
21
|
+
members = {'F': False, 'T': True}
|
|
22
|
+
box = diamond = lambda self: self
|
|
23
|
+
def __and__(self, other, /): return self and other
|
|
24
|
+
def __or__(self, other, /): return self or other
|
|
25
|
+
def __invert__(self): return type(self)(not self)
|
|
26
|
+
def __reduce__(self): return type(self), (self.value,)
|
|
27
|
+
K3, LP = map(lambda n, g: _FastEnumLogicMeta(n, (), {'members': {'F': -1, 'I': 0, 'T': 1}, '__and__': lambda self, other, /: min(self, other), '__or__': lambda self, other, /: max(self, other), '__invert__': lambda self: type(self)(-self.value), '__bool__': lambda self: self.value >= (n == 'K'), 'gullibility': g, 'consensus': lambda self, other, /: self if self is other else other if self is (I := type(self).I) else self if other is I else I, 'normalized': lambda self: Fraction(self.value+1, 2), 'from_normalized': classmethod(lambda cls, val: cls(int(val*2-1)))}), ('K3', 'LP'), (lambda self, other, /: self if self is other else type(self).I, lambda self, other, /: self if self is other else other if self is (I := type(self).I) else self if other is I else type(self).F))
|
|
28
|
+
class BI3(metaclass=_FastEnumLogicMeta):
|
|
29
|
+
members = {'F': -1, 'I': 0, 'T': 1}
|
|
30
|
+
def __and__(self, other, /): return I if (I := __class__.I) in (self, other) else type(self)(min(self.value, other.value))
|
|
31
|
+
def __or__(self, other, /): return I if (I := __class__.I) in (self, other) else type(self)(max(self.value, other.value))
|
|
32
|
+
def __invert__(self): return type(self)(-self.value)
|
|
33
|
+
def implies(self, other, /): return I if (I := __class__.I) in (self, other) else __class__.F if self is (T := __class__.T) and other is __class__.F else T
|
|
34
|
+
def gullibility(self, other, /): return self if self is other else __class__.I
|
|
35
|
+
def consensus(self, other, /): return self if len(s := {self, other}) == 1 else s.discard(__class__.I) or (s.pop() if len(s) == 1 else __class__.I)
|
|
36
|
+
def normalized(self): return Fraction(self.value+1, 2)
|
|
37
|
+
@classmethod
|
|
38
|
+
def from_normalized(cls, val): return cls(int(val*2-1))
|
|
39
|
+
def __reduce__(self): return type(self), (self.value,)
|
|
40
|
+
class RM3(metaclass=_FastEnumLogicMeta):
|
|
41
|
+
members = {'F': -1, 'B': 0, 'T': 1}
|
|
42
|
+
def __and__(self, other, /): return type(self)(min(self.value, other.value))
|
|
43
|
+
def __or__(self, other, /): return type(self)(max(self.value, other.value))
|
|
44
|
+
def __invert__(self): return type(self)(-self.value)
|
|
45
|
+
def implies(self, other, /): return self if self is other else T if (self is (F := __class__.F))^(other is (T := __class__.T)) else F
|
|
46
|
+
def normalized(self): return Fraction(self.value+1, 2)
|
|
47
|
+
@classmethod
|
|
48
|
+
def from_normalized(cls, val): return cls(int(val*2-1))
|
|
49
|
+
def __reduce__(self): return type(self), (self.value,)
|
|
50
|
+
def _check_names(n: tuple[str, ...], k: int|None, p: str):
|
|
51
|
+
if k is None: k = len(n)
|
|
52
|
+
elif n: raise ValueError('do not pass k with names')
|
|
53
|
+
if k < 2: raise ValueError('k should be >= 2')
|
|
54
|
+
return k, iter(n or map((p+'%s').__mod__, range(k)))
|
|
55
|
+
def _to_members(K: int, N): return {x: Fraction(i, K-1) for i, x in enumerate(N)}
|
|
56
|
+
def gödel_logic(*names, k=None, prefix='x_', clsname=None): K, N = _check_names(names, k, prefix); return _FastEnumLogicMeta(clsname or f'G{K}', (), {'members': _to_members(K, N), '__and__': lambda self, other, /: type(self)(min(self.value, other.value)), '__or__': lambda self, other, /: type(self)(max(self.value, other.value)), '__invert__': lambda self: type(self)(self.value == 0), 'implies': lambda self, other, /: type(self)(1) if self.value <= other.value else other, '__doc__': f"Godel's {K}-valued logic. See https://plato.stanford.edu/entries/logic-manyvalued/#GodLog."})
|
|
57
|
+
G3, SmT = gödel_logic('F', 'NF', 'T'), gödel_logic('F', 'NF', 'T', clsname='SmT')
|
|
58
|
+
def łukasiewicz_logic(*names, k=None, prefix='x_', clsname=None): K, N = _check_names(names, k, prefix); return _FastEnumLogicMeta(clsname or f'L{K}', (), {'members': _to_members(K, N), 'implies': (f := lambda self, other, /: type(self)(1+min(0, other.value-self.value))), '__invert__': lambda self: type(self)(1-self.value), '__and__': lambda self, other, /: f(f(self, other), other), '__or__': lambda self, other, /: ~(~self&~other), 'strong_disjunction': lambda self, other, /: f(~self, other), 'strong_conjunction': lambda self, other, /: ~f(self, ~other), 'diamond': (d := lambda self: f(~self, self)), 'box': lambda self: ~d(~self), 'doubtful': lambda self: self.iff(~self)})
|
|
59
|
+
L3 = łukasiewicz_logic('F', 'U', 'T')
|
|
60
|
+
def post_logic(*names, k=None, prefix='x_', clsname=None): K, N = _check_names(names, k, prefix); U = Fraction(1, K-1); return _FastEnumLogicMeta(clsname or f'P{K}', (), {'members': _to_members(K, N), '__invert__': lambda self: type(self)(v-U if (v := self.value) else 1), '__and__': lambda self, other, /: type(self)(min(self.value, other.value)), '__or__': lambda self, other, /: type(self)(max(self.value, other.value))})
|
|
61
|
+
P3 = post_logic('F', 'U', 'T')
|
|
62
|
+
class B4(metaclass=_FastEnumLogicMeta):
|
|
63
|
+
members = {'F': 0, 'N': 1, 'B': 2, 'T': 3}
|
|
64
|
+
def __invert__(self): return self if self in (__class__.B, __class__.N) else type(self)(3-self.value)
|
|
65
|
+
def __bool__(self): return self.value >= 2
|
|
66
|
+
def __and__(self, other, /):
|
|
67
|
+
if (F := __class__.F) in (self, other): return F
|
|
68
|
+
if self is (T := __class__.T): return other
|
|
69
|
+
if other is T: return self
|
|
70
|
+
return self if self is other else F
|
|
71
|
+
def __or__(self, other, /):
|
|
72
|
+
if (T := __class__.T) in (self, other): return T
|
|
73
|
+
if self is (F := __class__.F): return other
|
|
74
|
+
if other is F: return self
|
|
75
|
+
return self if self is other else T
|
|
76
|
+
def implies(self, other, /): return ~self|other
|
|
77
|
+
def gullibility(self, other, /): return self if self is other else __class__.N
|
|
78
|
+
def consensus(self, other, /): return self if len(s := {self, other}) == 1 else s.discard(__class__.N) or (s.pop() if len(s) == 1 else __class__.B)
|
|
79
|
+
def normalized(self): return Fraction(self.value, 3)
|
|
80
|
+
@classmethod
|
|
81
|
+
def from_normalized(cls, val): return cls(int(val*3))
|
|
82
|
+
Π, Π_aleph_0 = map(lambda name, meta: meta(name, (), {'__and__': lambda self, other, /: type(self)(self.value*other.value), '__or__': lambda self, other, /: type(self)(min(self.value, other.value)), '__invert__': lambda self: self.implies(type(self).F), 'implies': lambda self, other, /: type(self)(b/a if (a := self.value) > (b := other.value) else 1)}), ('Π', 'Π_aleph_0'), (_DecimalLogicMeta, _RationalLogicMeta))
|
|
83
|
+
G_inf, G_aleph_0 = map(lambda name, meta: meta(name, (), {'__and__': lambda self, other, /: type(self)(self.value*other.value), '__or__': lambda self, other, /: type(self)(min(self.value, other.value)), '__invert__': lambda self: type(self)(self.value == 0), 'implies': lambda self, other, /: type(self).T if self.value <= other.value else other}), ('G_inf', 'G_aleph_0'), (_DecimalLogicMeta, _RationalLogicMeta))
|
|
84
|
+
L_inf, L_aleph_0 = map(lambda name, meta: meta(name, (), {'implies': lambda self, other, /: type(self)(1+min(0, other.value-self.value)), '__invert__': lambda self: type(self)(1-self.value), '__and__': lambda self, other, /: self.implies(other).implies(other), '__or__': lambda self, other, /: ~(~self&~other), 'strong_disjunction': lambda self, other, /: (~self).implies(other), 'strong_conjunction': lambda self, other, /: ~self.implies(~other), 'diamond': lambda self: (~self).implies(self), 'box': lambda self: ~(~self).diamond(), 'doubtful': lambda self: self.iff(~self)}), ('L_inf', 'L_aleph_0'), (_DecimalLogicMeta, _RationalLogicMeta))
|
|
85
|
+
def t_norm_logic(*, name=None, rational=False, **k):
|
|
86
|
+
def dec(strong_conjunctionf):
|
|
87
|
+
x, y, z = map(Decimal, ('0.3', '0.7', '0.5'))
|
|
88
|
+
if strong_conjunctionf(x, y) != strong_conjunctionf(y, x): raise ValueError('t-norm must be commutative')
|
|
89
|
+
if strong_conjunctionf(x, Decimal(1)) != x: raise ValueError('degree 1 must be neutral element')
|
|
90
|
+
if strong_conjunctionf(Decimal('0.2'), z) > strong_conjunctionf(x, z): raise ValueError('t-norm must be non-decreasing')
|
|
91
|
+
def implies(self, other, /):
|
|
92
|
+
f = Decimal('0.001').__mul__
|
|
93
|
+
if self is (_ := type(self)).F: return _.T
|
|
94
|
+
s, u, v = 0, self.value, other.value
|
|
95
|
+
for i in range(1001):
|
|
96
|
+
if strong_conjunctionf(u, z := f(i)) <= v: s = z
|
|
97
|
+
return type(self)(s)
|
|
98
|
+
return (_RationalLogicMeta if rational else _DecimalLogicMeta)(name or strong_conjunctionf.__name__, (), {'strong_conjunction': lambda self, other, /: type(self)(strong_conjunctionf(self.value, other.value)), 'implies': implies, '__invert__': lambda self: self.implies(self.F), '__and__': lambda self, other: type(self)(min(self.value, other.value)), '__or__': lambda self, other, /: type(self)(max(self.value, other.value))}|k)
|
|
99
|
+
return dec
|
|
100
|
+
def logic_from_implication(*, name=None, rational=False, **k): return lambda impliesf: (_RationalLogicMeta if rational else _DecimalLogicMeta)(name or impliesf.__name__, (), {'implies': impliesf, '__invert__': lambda self: self.implies(self.F), '__and__': lambda self, other: type(self)(min(self.value, other.value)), '__or__': lambda self, other, /: type(self)(max(self.value, other.value))}|k)
|
|
101
|
+
decimal_t_norm_logic, rational_t_norm_logic, decimal_logic_from_implication, rational_logic_from_implication = t_norm_logic(), t_norm_logic(rational=True), logic_from_implication(), logic_from_implication(rational=True)
|
|
102
|
+
NP, NP_aleph_0 = t_norm_logic(name='NP')(f := lambda u, v: min(u, v) if u+v > 1 else Decimal()), t_norm_logic(name='NP_aleph_0', rational=True)(f)
|
|
103
|
+
class protocols(metaclass=_SubmoduleMeta, _supermodule_default_name_='logics'): __all__, __dir__ = FAKE_PROTOCOLS_TUPLE, (lambda: FAKE_PROTOCOLS_TUPLE)
|
|
104
|
+
for _ in FAKE_PROTOCOLS_TUPLE: setattr(protocols, _, _FakeProtocolMeta(_))
|
mvlogics/__init__.pyi
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
'''Implementations of various logics, not necessarily with two truth values. A logic is a propositional calculus, with an example being Aristotle's
|
|
2
|
+
logical calculus, where the only truth values are T and F and the law of the excluded middle holds. Logics do not support subclassing, analogously
|
|
3
|
+
to the built-in type bool. Members of all classes in this module are lazily generated to avoid significant memory overhead.'''
|
|
4
|
+
from typing import final, overload, Self, ClassVar, NoReturn, TypeGuard, Callable, Literal, Any
|
|
5
|
+
from fractions import Fraction
|
|
6
|
+
from decimal import Decimal
|
|
7
|
+
from .protocols import MemberlessLogicBase, LogicBase, StrictLogicBase, GödelLogic, ŁukasiewiczLogic, PostLogic, DecimalLogicBase, RationalLogicBase, TNormLogic, RationalTNormLogic, _L
|
|
8
|
+
REQUIRED_ATTRS: frozenset[str]
|
|
9
|
+
RECOMMENDED_METHODS: frozenset[str]
|
|
10
|
+
MIXIN_METHODS: frozenset[str]
|
|
11
|
+
EXTENSION_METHODS: frozenset[str]
|
|
12
|
+
FORBIDDEN: frozenset[str]
|
|
13
|
+
ALL_METHODS: frozenset[str]
|
|
14
|
+
FAKE_PROTOCOLS: frozenset[str]
|
|
15
|
+
ALL_LOGICS: frozenset[str]
|
|
16
|
+
FAKE_PROTOCOLS_TUPLE: tuple[str, ...]
|
|
17
|
+
ALL_LOGICS_TUPLE: tuple[str, ...]
|
|
18
|
+
__all__: tuple[str, ...]
|
|
19
|
+
def convert(member: MemberlessLogicBase, cls: type[_L]) -> _L: ...
|
|
20
|
+
def is_logic(typ: type) -> TypeGuard[type[MemberlessLogicBase[Any]]]: ...
|
|
21
|
+
def is_logic_member(obj: object) -> TypeGuard[MemberlessLogicBase[Any]]: ...
|
|
22
|
+
def is_builtin_logic(typ: type) -> TypeGuard[type[LogicBase[Any]|Unit]]: ...
|
|
23
|
+
def is_builtin_logic_member(obj: object) -> TypeGuard[LogicBase[Any]|Unit]: ...
|
|
24
|
+
@final
|
|
25
|
+
class Unit(MemberlessLogicBase):
|
|
26
|
+
'''An implementation of a single-valued logic. May be useful as a base case in various recursive operations.'''
|
|
27
|
+
T: ClassVar[Self]
|
|
28
|
+
def __new__(cls) -> Self: ...
|
|
29
|
+
def __and__(self, other: Self, /): ...
|
|
30
|
+
def __or__(self, other: Self, /) -> Self: ...
|
|
31
|
+
def __invert__(self) -> Self: ...
|
|
32
|
+
def box(self) -> Self: ...
|
|
33
|
+
def diamond(self) -> Self: ...
|
|
34
|
+
def gullibility(self, other: Self, /) -> Self: ...
|
|
35
|
+
def consensus(self, other: Self, /) -> Self: ...
|
|
36
|
+
def __bool__(self) -> NoReturn: ...
|
|
37
|
+
@final
|
|
38
|
+
class Boolean(LogicBase[bool]):
|
|
39
|
+
'''Boolean or Aristotelian logic, where the law of the excluded middle holds.
|
|
40
|
+
Actually just a wrapper around the built-in class bool which satisfies the interface.'''
|
|
41
|
+
T: ClassVar[Self]
|
|
42
|
+
F: ClassVar[Self]
|
|
43
|
+
def __and__(self, other: Self, /) -> Self: ...
|
|
44
|
+
def __or__(self, other: Self, /) -> Self: ...
|
|
45
|
+
def __invert__(self) -> Self: ...
|
|
46
|
+
def box(self) -> Self: ...
|
|
47
|
+
def diamond(self) -> Self: ...
|
|
48
|
+
@final
|
|
49
|
+
class K3(StrictLogicBase[int]):
|
|
50
|
+
'''Kleene's strong logic of indeterminancy (K_3), in which besides the truth values T and F, a new 'indeterminate' truth value I is introduced.
|
|
51
|
+
T is the only designated truth value.'''
|
|
52
|
+
T: ClassVar[Self]
|
|
53
|
+
I: ClassVar[Self]
|
|
54
|
+
F: ClassVar[Self]
|
|
55
|
+
def __and__(self, other: Self, /) -> Self: ...
|
|
56
|
+
def __or__(self, other: Self, /) -> Self: ...
|
|
57
|
+
def __invert__(self) -> Self: ...
|
|
58
|
+
def gullibility(self, other: Self, /): ...
|
|
59
|
+
def consensus(self, other: Self, /) -> Self: ...
|
|
60
|
+
@final
|
|
61
|
+
class LP(StrictLogicBase[int]):
|
|
62
|
+
'''Priest's 'logic of paradox' (P_3), provisionally named LP because P_3 refers to ternary Post logic here. The truth tables are equivalent to those of Kleene's, except I is also designated as a truth value. The gullibility operation is thus not as well-defined as in K_3, and in the case that one operand is T and the other F, the arbitrary convention to return F is chosen.'''
|
|
63
|
+
T: ClassVar[Self]
|
|
64
|
+
I: ClassVar[Self]
|
|
65
|
+
F: ClassVar[Self]
|
|
66
|
+
def __and__(self, other: Self, /) -> Self: ...
|
|
67
|
+
def __or__(self, other: Self, /) -> Self: ...
|
|
68
|
+
def __invert__(self) -> Self: ...
|
|
69
|
+
def gullibility(self, other: Self, /): ...
|
|
70
|
+
def consensus(self, other: Self, /) -> Self: ...
|
|
71
|
+
@final
|
|
72
|
+
class BI3(StrictLogicBase[int]):
|
|
73
|
+
'''Dmitry Bochvar's internal three-value logic, also known as Kleene's weak three-value logic. The indeterminate truth value is contagious in the sense that it propagates as the result of any operation that involves it.'''
|
|
74
|
+
T: ClassVar[Self]
|
|
75
|
+
I: ClassVar[Self]
|
|
76
|
+
F: ClassVar[Self]
|
|
77
|
+
def __and__(self, other: Self, /) -> Self: ...
|
|
78
|
+
def __or__(self, other: Self, /) -> Self: ...
|
|
79
|
+
def __invert__(self) -> Self: ...
|
|
80
|
+
def gullibility(self, other: Self, /): ...
|
|
81
|
+
def consensus(self, other: Self, /) -> Self: ...
|
|
82
|
+
@final
|
|
83
|
+
class RM3(LogicBase[int]):
|
|
84
|
+
'''The R-mingle 3 logic, whose significance lies in its material implication implementation. The axiom of weakening does not hold in RM3.'''
|
|
85
|
+
T: ClassVar[Self]
|
|
86
|
+
B: ClassVar[Self]
|
|
87
|
+
F: ClassVar[Self]
|
|
88
|
+
def __and__(self, other: Self, /) -> Self: ...
|
|
89
|
+
def __or__(self, other: Self, /) -> Self: ...
|
|
90
|
+
def __invert__(self) -> Self: ...
|
|
91
|
+
@final
|
|
92
|
+
class B4(StrictLogicBase[int]):
|
|
93
|
+
'''Belnap's logic B_4, a combination of K_3 and P_3, such that the overdetermined I is called B for 'both', and the underdetermined N for 'neither' The truth tables are derived accordingly.'''
|
|
94
|
+
T: ClassVar[Self]
|
|
95
|
+
B: ClassVar[Self]
|
|
96
|
+
N: ClassVar[Self]
|
|
97
|
+
F: ClassVar[Self]
|
|
98
|
+
def __and__(self, other: Self, /) -> Self: ...
|
|
99
|
+
def __or__(self, other: Self, /) -> Self: ...
|
|
100
|
+
def __invert__(self) -> Self: ...
|
|
101
|
+
def gullibility(self, other: Self, /): ...
|
|
102
|
+
def consensus(self, other: Self, /) -> Self: ...
|
|
103
|
+
@final
|
|
104
|
+
class SmT(GödelLogic):
|
|
105
|
+
'''Smetanov logic, also known as the logic of here and there and Gödel G3 logic. Introduced by Arend Heyting in 1930 to study intuitionistic logic, it is a three-valued intermediate logic where the intermediate value can be understood as 'not false'.'''
|
|
106
|
+
T: ClassVar[Self]
|
|
107
|
+
NF: ClassVar[Self]
|
|
108
|
+
F: ClassVar[Self]
|
|
109
|
+
@final
|
|
110
|
+
class G3(GödelLogic):
|
|
111
|
+
'''A three-valued logic of Gödel's, also known as Smetanov logic and the logic of here and there. Belongs to a larger family of 'Gödel' logics G_k with truth values 0, 1/(k-1), 2/(k-1), ..., (k-2)/(k-1), 1, with 1 designated as a 'true' truth value.'''
|
|
112
|
+
T: ClassVar[Self]
|
|
113
|
+
NF: ClassVar[Self]
|
|
114
|
+
F: ClassVar[Self]
|
|
115
|
+
@final
|
|
116
|
+
class L3(ŁukasiewiczLogic):
|
|
117
|
+
'''Jan Łukasiewicz's three-valued logic; the truth values for 0, 1/2, 1 are called F, U and T respectively.'''
|
|
118
|
+
T: ClassVar[Self]
|
|
119
|
+
U: ClassVar[Self]
|
|
120
|
+
F: ClassVar[Self]
|
|
121
|
+
@final
|
|
122
|
+
class P3(PostLogic):
|
|
123
|
+
'''Ternary Post logic, with a cyclic implementation of the negation operator.'''
|
|
124
|
+
T: ClassVar[Self]
|
|
125
|
+
U: ClassVar[Self]
|
|
126
|
+
F: ClassVar[Self]
|
|
127
|
+
@final
|
|
128
|
+
class Π(DecimalLogicBase): '''Product logic, with truth values between 0 and 1. For precision, please pass in a string (e.g. '3.14159' instead of 3.14159) to the constructor; however, passing an int, float or decimal.Decimal instance is also acceptable.'''
|
|
129
|
+
@final
|
|
130
|
+
class G_inf(DecimalLogicBase): '''Gödel's infinite-valued logic, with real numbers between 0 and 1 as truth values.'''
|
|
131
|
+
@final
|
|
132
|
+
class L_inf(DecimalLogicBase):
|
|
133
|
+
'''Łukasiewicz's infinite-valued logic, with real numbers between 0 and 1 as truth values.'''
|
|
134
|
+
def strong_disjunction(self, other: Self, /) -> Self: ...
|
|
135
|
+
def strong_conjunction(self, other: Self, /) -> Self: ...
|
|
136
|
+
def diamond(self) -> Self: ...
|
|
137
|
+
def box(self) -> Self: ...
|
|
138
|
+
def doubtful(self) -> Self: ...
|
|
139
|
+
@final
|
|
140
|
+
class NP(TNormLogic): '''A t-norm logic with the nilpotent minimum norm as the implication operator.'''
|
|
141
|
+
@final
|
|
142
|
+
class Π_aleph_0(RationalLogicBase): '''Product logic, with rational numbers between 0 and 1 as truth values. Pass in what Fraction takes to the constructor.'''
|
|
143
|
+
@final
|
|
144
|
+
class G_aleph_0(RationalLogicBase): '''Gödel's infinite-valued logic, with rational numbers between 0 and 1 as truth values.'''
|
|
145
|
+
@final
|
|
146
|
+
class L_aleph_0(RationalLogicBase):
|
|
147
|
+
'''Łukasiewicz's infinite-valued logic, with rational numbers between 0 and 1 as truth values.'''
|
|
148
|
+
def strong_disjunction(self, other: Self, /) -> Self: ...
|
|
149
|
+
def strong_conjunction(self, other: Self, /) -> Self: ...
|
|
150
|
+
def diamond(self) -> Self: ...
|
|
151
|
+
def box(self) -> Self: ...
|
|
152
|
+
def doubtful(self) -> Self: ...
|
|
153
|
+
@final
|
|
154
|
+
class NP_aleph_0(RationalTNormLogic): '''A t-norm logic with the nilpotent minimum norm as the implication operator and rational truth values only.'''
|
|
155
|
+
@overload
|
|
156
|
+
def gödel_logic(name_1: str, name_2: str, /, *names: str, clsname: str|None=...) -> type[GödelLogic]: '''Returns a Gödel logic class with name clsname and truth values of names name_1 (0), name_2 (1/(k-1)), ..., name_(k-1) ((k-2)/(k-1)), name_k (1).'''
|
|
157
|
+
@overload
|
|
158
|
+
def gödel_logic(*, k: int, prefix: str='x_', clsname: str|None=...) -> type[GödelLogic]: ...
|
|
159
|
+
@overload
|
|
160
|
+
def łukasiewicz_logic(name_1: str, name_2: str, /, *names: str, clsname: str|None=...) -> type[ŁukasiewiczLogic]: '''Returns a Łukasiewicz logic class with name clsname and truth values of names name_1 (0), name_2 (1/(k-1)), ..., name_(k-1) ((k-2)/(k-1)), name_k (1).'''
|
|
161
|
+
@overload
|
|
162
|
+
def łukasiewicz_logic(*, k: int, prefix: str='x_', clsname: str|None=...) -> type[ŁukasiewiczLogic]: ...
|
|
163
|
+
@overload
|
|
164
|
+
def post_logic(name_1: str, name_2: str, /, *names: str, clsname: str|None=...) -> type[PostLogic]: '''Returns a Postlogic class with name `clsname` and truth values of names `name_1` (0), `name_2` (1/(k-1)), ..., `name_(k-1)` ((k-2)/(k-1)), `name_k` (1).'''
|
|
165
|
+
@overload
|
|
166
|
+
def post_logic(*, k: int, prefix: str='x_', clsname: str|None=...) -> type[PostLogic]: ...
|
|
167
|
+
@overload
|
|
168
|
+
def t_norm_logic(*, name: str, rational: Literal[False]=False, **additional: Any) -> Callable[[Callable[[Decimal, Decimal], Decimal]], type[TNormLogic]]: '''A decorator factory whose products return t-norm logic classes given the strong conjunction operator, given whether the members should be constrained to rational numbers.'''
|
|
169
|
+
@overload
|
|
170
|
+
def t_norm_logic(*, name: str, rational: Literal[True], **additional: Any) -> Callable[[Callable[[Fraction, Fraction], Fraction]], type[RationalTNormLogic]]: ...
|
|
171
|
+
@overload
|
|
172
|
+
def t_norm_logic(*, rational: Literal[False]=False, **additional: Any) -> Callable[[Callable[[Decimal, Decimal], Decimal]], type[TNormLogic]]: ...
|
|
173
|
+
@overload
|
|
174
|
+
def t_norm_logic(*, rational: Literal[True], **additional: Any) -> Callable[[Callable[[Fraction, Fraction], Fraction]], type[RationalTNormLogic]]: ...
|
|
175
|
+
@overload
|
|
176
|
+
def logic_from_implication(*, name: str, rational: Literal[False]=False, **additional: Any) -> Callable[[Callable[[Decimal, Decimal], Decimal]], type[DecimalLogicBase]]: '''A decorator factory whose products return logic classes given the implication operator only, given whether the members should be constrained to rational numbers.'''
|
|
177
|
+
@overload
|
|
178
|
+
def logic_from_implication(*, name: str, rational: Literal[True], **additional: Any) -> Callable[[Callable[[Fraction, Fraction], Fraction]], type[RationalLogicBase]]: ...
|
|
179
|
+
@overload
|
|
180
|
+
def logic_from_implication(*, rational: Literal[False]=False, **additional: Any) -> Callable[[Callable[[Decimal, Decimal], Decimal]], type[DecimalLogicBase]]: ...
|
|
181
|
+
@overload
|
|
182
|
+
def logic_from_implication(*, rational: Literal[True], **additional: Any) -> Callable[[Callable[[Fraction, Fraction], Fraction]], type[RationalLogicBase]]: ...
|
|
183
|
+
def decimal_t_norm_logic(strong_conjunctionf: Callable[[Decimal, Decimal], Decimal]) -> type[TNormLogic]: '''Version of t_norm_logic specific to decimals.'''
|
|
184
|
+
def rational_t_norm_logic(strong_conjunctionf: Callable[[Fraction, Fraction], Fraction]) -> type[RationalTNormLogic]: '''Version of t_norm_logic specific to fractions.'''
|
|
185
|
+
def decimal_logic_from_implication(impliesf: Callable[[Decimal, Decimal], Decimal]) -> type[DecimalLogicBase]: '''Version of logic_from_implication specific to decimals.'''
|
|
186
|
+
def rational_logic_from_implication(impliesf: Callable[[Fraction, Fraction], Fraction]) -> type[RationalLogicBase]: '''Version of logic_from_implication specific to fractions.'''
|
mvlogics/base.py
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from weakref import WeakKeyDictionary
|
|
3
|
+
from fractions import Fraction
|
|
4
|
+
from decimal import Decimal, getcontext
|
|
5
|
+
def _weak_cache(name=None):
|
|
6
|
+
def dec(f):
|
|
7
|
+
def g(self, _=WeakKeyDictionary()):
|
|
8
|
+
if (r := _.get(self, s := _SlowEnumLogicMeta.MemberContainer._NOT_GENERATED)) is s: _[self] = r = f(self)
|
|
9
|
+
return r
|
|
10
|
+
g.__name__ = name or f.__name__; return g
|
|
11
|
+
return dec
|
|
12
|
+
_normalized_cache, _repr_cache = map(_weak_cache, ('normalized', '__repr__'))
|
|
13
|
+
REQUIRED_ATTRS, FORBIDDEN = map(frozenset, (('__and__', '__or__', '__invert__'), ('__new__', 'value')))
|
|
14
|
+
(_singleton_new := lambda cls: _singleton_new.cache.get(cls, False) or object.__new__(cls)).cache, getcontext().prec = WeakKeyDictionary(), 100
|
|
15
|
+
_all, ALL_METHODS, ALL_LOGICS, FAKE_PROTOCOLS = ('ALL_METHODS', 'FORBIDDEN', 'ALL_LOGICS', 'ALL_LOGICS_TUPLE', 'FAKE_PROTOCOLS', 'FAKE_PROTOCOLS_TUPLE', 'REQUIRED_ATTRS', 'RECOMMENDED_METHODS', 'MIXIN_METHODS', 'EXTENSION_METHODS', 'protocols', 'is_logic', 'is_logic_member', 'is_builtin_logic', 'is_builtin_logic_member', 'convert', 'gödel_logic', 'łukasiewicz_logic', 'post_logic', 't_norm_logic', 'logic_from_implication', 'decimal_t_norm_logic', 'rational_t_norm_logic', 'decimal_logic_from_implication', 'rational_logic_from_implication', *(ALL_LOGICS_TUPLE := ('Unit', 'Boolean', 'K3', 'LP', 'BI3', 'RM3', 'G3', 'SmT', 'L3', 'P3', 'B4', 'Π', 'Π_aleph_0', 'G_inf', 'G_aleph_0', 'L_inf', 'L_aleph_0', 'NP', 'NP_aleph_0'))), REQUIRED_ATTRS|(RECOMMENDED_METHODS := frozenset(('implies', '__bool__', 'gullibility', 'consensus')))|(MIXIN_METHODS := frozenset(('iff', 'implies', '__pos__', '__neg__', '__xor__', 'value', 'nand', 'nor', 'xnor', 'abjunction', 'converse_implies', 'converse_abjunction')))|(EXTENSION_METHODS := frozenset(('strong_disjunction', 'strong_conjunction', 'diamond', 'box', 'doubtful'))), frozenset(ALL_LOGICS_TUPLE), frozenset(FAKE_PROTOCOLS_TUPLE := ('MemberlessLogicBase', 'AbstractLogicBase', 'LogicBase', 'InfiniteLogicBase', 'DecimalLogicBase', 'RationalLogicBase', 'StrictLogicBase', 'GödelLogic', 'ŁukasiewiczLogic', 'PostLogic', 'TNormLogic', 'RationalTNormLogic'))
|
|
16
|
+
class _SubmoduleMeta(type):
|
|
17
|
+
def __new__(mcls, name, bases, namespace, /, *, _supermodule_default_name_='<unknown>'):
|
|
18
|
+
if bases: raise TypeError('Submodule cannot inherit from other classes')
|
|
19
|
+
try: name = f'{sys._getframemodulename(1) or _supermodule_default_name_}.{name}'
|
|
20
|
+
except AttributeError: name = f'{_supermodule_default_name_}.{name}'
|
|
21
|
+
sys.modules[name] = r = type(sys)(name, namespace.pop('__doc__', None)); return r
|
|
22
|
+
class _AllLogicMeta(type):
|
|
23
|
+
__defaults, __repr__ = None, _repr_cache(lambda cls: f'logics.{cls.__name__}')
|
|
24
|
+
def __new__(mcls, name, bases, namespace, /, **k):
|
|
25
|
+
if bases: raise ValueError('logics cannot inherit from anything')
|
|
26
|
+
if not REQUIRED_ATTRS.issubset(namespace): raise TypeError('missing methods')
|
|
27
|
+
return super().__new__(mcls, name, bases, mcls.__default_factory__()|namespace, **k)
|
|
28
|
+
@classmethod
|
|
29
|
+
def __default_factory__(mcls):
|
|
30
|
+
if (r := mcls.__defaults) is None: mcls.__defaults = r = {'__xor__': lambda self, other, /: (self&~other)|(other&~self), 'implies': lambda self, other, /: ~self|other, 'iff': (g := lambda self, other: self.implies(other)&other.implies(self)), 'nand': lambda self, other, /: ~(self&other), 'nor': lambda self, other, /: ~(self|other), 'xnor': g, 'abjunction': lambda self, other, /: ~self.implies(other), 'converse_implies': lambda self, other, /: self|~other, 'converse_abjunction': lambda self, other, /: other&~self, '__bool__': lambda self: self.value == 1, '__pos__': lambda self: self, 'normalized': _normalized_cache(lambda self: Fraction(self.value)), 'from_normalized': classmethod(lambda cls, val: cls(val)), 'from_logic_member': classmethod(lambda cls, member: cls.from_normalized(member.normalized())), 'convert_to': lambda self, cls: cls.from_normalized(self.normalized())}
|
|
31
|
+
return r
|
|
32
|
+
class _InfLogicMetaBase(_AllLogicMeta):
|
|
33
|
+
@property
|
|
34
|
+
def T(cls): return cls.from_normalized(Fraction(1))
|
|
35
|
+
@property
|
|
36
|
+
def F(cls): return cls.from_normalized(Fraction())
|
|
37
|
+
verum, falsum = T, F
|
|
38
|
+
@classmethod
|
|
39
|
+
def _ret_new_and_value(mcls): raise NotImplementedError('do not use this metaclass; inherit from it and implement this method or use either _DecimalLogicMeta or _RationalLogicMeta')
|
|
40
|
+
@classmethod
|
|
41
|
+
def __default_factory__(mcls): return _AllLogicMeta.__default_factory__()|{'members': {}, '__repr__': _repr_cache(lambda self: f'{type(self).__name__}({self.value})')}|mcls._ret_new_and_value()
|
|
42
|
+
class _DecimalLogicMeta(_InfLogicMetaBase):
|
|
43
|
+
@classmethod
|
|
44
|
+
def _ret_new_and_value(mcls):
|
|
45
|
+
_ = WeakKeyDictionary()
|
|
46
|
+
def __new__(cls, val='0', /):
|
|
47
|
+
if (v := (c := cls.members).get(d := Decimal(val), None)) is None: c[d] = v = object.__new__(cls); _[v] = d
|
|
48
|
+
return v
|
|
49
|
+
return {'__new__': __new__, 'value': property(_.__getitem__)}
|
|
50
|
+
class _RationalLogicMeta(_InfLogicMetaBase):
|
|
51
|
+
@classmethod
|
|
52
|
+
def _ret_new_and_value(mcls):
|
|
53
|
+
_ = WeakKeyDictionary()
|
|
54
|
+
def __new__(cls, /, *a):
|
|
55
|
+
if (v := (c := cls.members).get(f := Fraction(*a), None)) is None: c[f] = v = object.__new__(cls); _[v] = f
|
|
56
|
+
return v
|
|
57
|
+
return {'__new__': __new__, 'value': property(_.__getitem__)}
|
|
58
|
+
class _SlowEnumLogicMeta(_AllLogicMeta):
|
|
59
|
+
class MemberContainer:
|
|
60
|
+
__cache, __cache2, _NOT_GENERATED = WeakKeyDictionary(), WeakKeyDictionary(), type('NotGenerated', (), {'__new__': _singleton_new, '__repr__': lambda _, /: '<not generated>'})()
|
|
61
|
+
def __init__(self, values): self.__values, self.value_from_name, self.name_from_value, self.names = dict.fromkeys(values.values(), self._NOT_GENERATED), values.__getitem__, {v: k for k, v in values.items()}.__getitem__, tuple(values.keys())
|
|
62
|
+
def generate(self, value):
|
|
63
|
+
if (x := self.__values[value]) is self._NOT_GENERATED: self.__values[value] = x = object.__new__(self.typ); self.__cache[x], self.__cache2[x] = value, self.name_from_value(value)
|
|
64
|
+
return x
|
|
65
|
+
def from_name(self, name):
|
|
66
|
+
if (x := self.__values[v := self.value_from_name(name)]) is self._NOT_GENERATED: self.__values[v] = x = object.__new__(self.typ); self.__cache[x], self.__cache2[x] = v, name
|
|
67
|
+
return x
|
|
68
|
+
def member_values(self): yield from self.__values.keys()
|
|
69
|
+
def __set_name__(self, owner, name, /): assert name == 'members'; self.typ = owner
|
|
70
|
+
@_repr_cache
|
|
71
|
+
def __repr__(self): return f'({', '.join(map(lambda i: str(self.generate(i)), self.__values))})'
|
|
72
|
+
def __iter__(self): yield from map(self.generate, self.__values)
|
|
73
|
+
def __getattr__(cls, name, /):
|
|
74
|
+
if name in cls.members.names: super().__setattr__(name, r := cls(name)); return r
|
|
75
|
+
raise AttributeError(f'class {cls.__name__} has no attribute {name!r}')
|
|
76
|
+
def __setattr__(cls, name, value, /):
|
|
77
|
+
if name in cls.members.names: raise TypeError(f'attribute {name!r} is read-only')
|
|
78
|
+
super().__setattr__(name, value)
|
|
79
|
+
def __new__(mcls, name, bases, namespace, /, **k):
|
|
80
|
+
if FORBIDDEN.intersection(namespace): raise TypeError('attempted to override forbidden attributes')
|
|
81
|
+
c = mcls.MemberContainer(namespace['members']); return super().__new__(mcls, name, bases, {'__repr__': _repr_cache(lambda self: f'{type(self).__name__}.{self.name}'), 'value': property(c._MemberContainer__cache.__getitem__), 'name': property(c._MemberContainer__cache2.__getitem__), '__neg__': namespace['__invert__']}|namespace|{'members': c, '__new__': lambda cls, v, /: c.from_name(v) if isinstance(v, str) else c.generate(v)}, **k)
|
|
82
|
+
class _FastEnumLogicMeta(_SlowEnumLogicMeta):
|
|
83
|
+
class MemberContainer(_SlowEnumLogicMeta.MemberContainer):
|
|
84
|
+
@_repr_cache
|
|
85
|
+
def __repr__(self): return f'({(n := self.typ.__name__)}.{f', {n}.'.join(self.names)})'
|
|
86
|
+
class _FakeProtocolMeta(type):
|
|
87
|
+
_cache, _meta_map, _requirement_map, _prefix_map, _mcont_allowed = [None]*12, (_AllLogicMeta, _AllLogicMeta, _SlowEnumLogicMeta, _InfLogicMetaBase, _DecimalLogicMeta, _RationalLogicMeta, _SlowEnumLogicMeta, _FastEnumLogicMeta, _FastEnumLogicMeta, _FastEnumLogicMeta, _DecimalLogicMeta, _RationalLogicMeta), tuple(map(frozenset, ((), ('values',), ('members', 'values'), (), (), (), ('gullibility', 'consensus'), (), ('strong_disjunction', 'strong_conjunction', 'diamond', 'box', 'doubtful'), (), ('strong_conjunction',), ('strong_conjunction',)))), ('', '', '', '', '', '', '', 'G', 'L', 'P', '', ''), frozenset((2, 6, 7, 8, 9))
|
|
88
|
+
def __new__(mcls, name, bases=(), namespace={}, /, **k):
|
|
89
|
+
try: r = (c := mcls._cache)[i := FAKE_PROTOCOLS_TUPLE.index(name)]
|
|
90
|
+
except ValueError: raise TypeError(f'cannot create protocol class with name {name!r}') from None
|
|
91
|
+
def __init_subclass__(_, /): raise TypeError(f'cannot inherit from protocol class {name!r}')
|
|
92
|
+
def __new__(*_): raise TypeError(f'cannot create instance of protocol {name!r}')
|
|
93
|
+
namespace['__init_subclass__'], namespace['__new__'] = __init_subclass__, __new__
|
|
94
|
+
if r is None: c[i] = r = super().__new__(mcls, name, bases, namespace, **k); r._idx, r._meth_cache = i, {}
|
|
95
|
+
return r
|
|
96
|
+
def __getattr__(cls, name, /):
|
|
97
|
+
if name == 'MemberContainer' and cls._idx in cls._mcont_allowed:
|
|
98
|
+
class MemberContainer(_FastEnumLogicMeta.MemberContainer):
|
|
99
|
+
def __new__(cls, values): raise TypeError(f'cannot instantiate MemberContainer with values {values!r}')
|
|
100
|
+
def __init_subclass__(cls): raise TypeError('cannot subclass MemberContainer')
|
|
101
|
+
cls.MemberContainer = MemberContainer; return MemberContainer
|
|
102
|
+
if name in ALL_METHODS:
|
|
103
|
+
if (r := (c := cls._meth_cache).get(name)) is None: exec('@property\n'*(name == 'value')+f'def {name}(*_): raise NotImplementedError("method {name!r} of protocol {cls.__name__!r} is abstract")', locals=c); r = c[name]
|
|
104
|
+
return r
|
|
105
|
+
raise AttributeError(f'class {cls.__name__!r} has no attribute {name!r}')
|
|
106
|
+
def __init_subclass__(mcls, /, **_): raise TypeError('cannot subclass _FakeProtocolMeta')
|
|
107
|
+
def __instancecheck__(cls, instance): return cls.__subclasscheck__(type(instance))
|
|
108
|
+
def __subclasscheck__(cls, sub): return isinstance(sub, cls._meta_map[i := cls._idx]) and sub.__name__.startswith(cls._prefix_map[i]) and (cls._requirement_map[i]|MIXIN_METHODS).issubset(sub.__dict__)
|
mvlogics/protocols.pyi
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
from typing import final, overload, Final, Generic, TypeVar, Self, Any, Generator, ClassVar, Sequence, TYPE_CHECKING
|
|
2
|
+
from fractions import Fraction
|
|
3
|
+
from decimal import Decimal
|
|
4
|
+
if TYPE_CHECKING:
|
|
5
|
+
_T = TypeVar('_T')
|
|
6
|
+
_L = TypeVar('_L', bound=MemberlessLogicBase)
|
|
7
|
+
_R = TypeVar('_R', bound=LogicBase)
|
|
8
|
+
class MemberlessLogicBase(Generic[_T]):
|
|
9
|
+
@classmethod
|
|
10
|
+
def from_normalized(cls, val: Fraction) -> Self: ...
|
|
11
|
+
@classmethod
|
|
12
|
+
def from_logic_member(cls, member: MemberlessLogicBase[Any]) -> Self: ...
|
|
13
|
+
def __and__(self, other: Self, /) -> Self: ...
|
|
14
|
+
def __or__(self, other: Self, /) -> Self: ...
|
|
15
|
+
def __invert__(self) -> Self: ...
|
|
16
|
+
def __pos__(self) -> Self: ...
|
|
17
|
+
def __neg__(self) -> Self: ...
|
|
18
|
+
def __xor__(self) -> Self: ...
|
|
19
|
+
def implies(self, other: Self, /) -> Self: ...
|
|
20
|
+
def iff(self, other: Self, /) -> Self: ...
|
|
21
|
+
def nor(self, other: Self, /) -> Self: ...
|
|
22
|
+
def nand(self, other: Self, /) -> Self: ...
|
|
23
|
+
def xnor(self, other: Self, /) -> Self: ...
|
|
24
|
+
def abjunction(self, other: Self, /) -> Self: ...
|
|
25
|
+
def converse_implies(self, other: Self, /) -> Self: ...
|
|
26
|
+
def converse_abjunction(self, other: Self, /) -> Self: ...
|
|
27
|
+
def normalized(self) -> Fraction: ...
|
|
28
|
+
def convert_to(self, cls: type[_L]) -> _L: ...
|
|
29
|
+
class AbstractLogicBase(MemberlessLogicBase[_T]):
|
|
30
|
+
@property
|
|
31
|
+
def value(self) -> _T: ...
|
|
32
|
+
def __new__(cls, v: _T, /) -> Self: ...
|
|
33
|
+
class LogicBase(AbstractLogicBase[_T]):
|
|
34
|
+
@final
|
|
35
|
+
class MemberContainer(Generic[_R]):
|
|
36
|
+
@property
|
|
37
|
+
def names(self) -> tuple[str, ...]: '''Is not a property at runtime.'''
|
|
38
|
+
def __init__(self, values: dict[str, _T]): ...
|
|
39
|
+
def generate(self, value: _T) -> _R: ...
|
|
40
|
+
def from_name(self, name: str) -> _R: ...
|
|
41
|
+
def value_from_name(self, name: str, /) -> _T: ...
|
|
42
|
+
def name_from_value(self, value: _T, /) -> str: ...
|
|
43
|
+
def member_values(self) -> Generator[_T, None, None]: ...
|
|
44
|
+
def __set_name__(self, owner: type, name: str, /) -> None: ...
|
|
45
|
+
def __iter__(self) -> Generator[_R, None, None]: ...
|
|
46
|
+
members: Final[MemberContainer[Self]]
|
|
47
|
+
class InfiniteLogicBase(AbstractLogicBase[_T]):
|
|
48
|
+
T: ClassVar[Self]
|
|
49
|
+
F: ClassVar[Self]
|
|
50
|
+
verum: ClassVar[Self]
|
|
51
|
+
falsum: ClassVar[Self]
|
|
52
|
+
members: Final[dict[_T, Self]]
|
|
53
|
+
class DecimalLogicBase(InfiniteLogicBase[Decimal]):
|
|
54
|
+
@overload
|
|
55
|
+
def __new__(cls, v: Decimal, /) -> Self: ...
|
|
56
|
+
@overload
|
|
57
|
+
def __new__(cls, v: float, /) -> Self: ...
|
|
58
|
+
@overload
|
|
59
|
+
def __new__(cls, v: str, /) -> Self: ...
|
|
60
|
+
@overload
|
|
61
|
+
def __new__(cls, v: tuple[int, Sequence[int], int], /) -> Self: ...
|
|
62
|
+
class RationalLogicBase(InfiniteLogicBase[Fraction]):
|
|
63
|
+
@overload
|
|
64
|
+
def __new__(cls, num: int, /) -> Self: ...
|
|
65
|
+
@overload
|
|
66
|
+
def __new__(cls, arg: str, /) -> Self: ...
|
|
67
|
+
@overload
|
|
68
|
+
def __new__(cls, num: float, /) -> Self: ...
|
|
69
|
+
@overload
|
|
70
|
+
def __new__(cls, num: Fraction, /) -> Self: ...
|
|
71
|
+
@overload
|
|
72
|
+
def __new__(cls, num: Decimal, /) -> Self: ...
|
|
73
|
+
@overload
|
|
74
|
+
def __new__(cls, num: int, dem: int, /) -> Self: ...
|
|
75
|
+
class StrictLogicBase(LogicBase[_T]):
|
|
76
|
+
def gullibility(self, other: Self, /) -> Self: ...
|
|
77
|
+
def consensus(self, other: Self, /) -> Self: ...
|
|
78
|
+
class GödelLogic(LogicBase[Fraction]): ...
|
|
79
|
+
class ŁukasiewiczLogic(LogicBase[Fraction]):
|
|
80
|
+
def strong_disjunction(self, other: Self, /) -> Self: ...
|
|
81
|
+
def strong_conjunction(self, other: Self, /) -> Self: ...
|
|
82
|
+
def diamond(self) -> Self: ...
|
|
83
|
+
def box(self) -> Self: ...
|
|
84
|
+
def doubtful(self) -> Self: ...
|
|
85
|
+
class PostLogic(LogicBase[Fraction]): ...
|
|
86
|
+
class TNormLogic(DecimalLogicBase):
|
|
87
|
+
def strong_conjunction(self, other: Self, /) -> Self: ...
|
|
88
|
+
class RationalTNormLogic(RationalLogicBase):
|
|
89
|
+
def strong_conjunction(self, other: Self, /) -> Self: ...
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mvlogics
|
|
3
|
+
Version: 0.9.0
|
|
4
|
+
Summary: Multi-valued logics.
|
|
5
|
+
Author-email: Jonathan Dung <jonathandung@yahoo.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/jonathandung/mvlogics
|
|
8
|
+
Project-URL: Repository, https://github.com/jonathandung/mvlogics.git
|
|
9
|
+
Keywords: mathematical,object-oriented
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Requires-Python: >=3.9
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
Provides-Extra: dev
|
|
16
|
+
Requires-Dist: black; extra == "dev"
|
|
17
|
+
Requires-Dist: flake8; extra == "dev"
|
|
18
|
+
Dynamic: license-file
|
|
19
|
+
|
|
20
|
+
# mvlogics
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
mvlogics/__init__.py,sha256=X112Qek4azgNyP6gAuNjgRckWOT8CUFd0cmC7a6htyc,11157
|
|
2
|
+
mvlogics/__init__.pyi,sha256=0y95DYMI4TgYRRcL1gz4nikevsq73plv95Zk4iBItIk,11802
|
|
3
|
+
mvlogics/base.py,sha256=YldQA3vClpPMhGcuZQDSJToce7hTyuhMl3qWPFsGnvE,10553
|
|
4
|
+
mvlogics/protocols.pyi,sha256=vb1E7-LvYTY_9L2FZM46WBdmtIhWpgUkMc1Z3fnNXI0,3850
|
|
5
|
+
mvlogics-0.9.0.dist-info/licenses/LICENSE,sha256=DIVhmXv1QFIoykQd8zmb-hEQ4vDvDBi3oteSatFMF-I,1089
|
|
6
|
+
mvlogics-0.9.0.dist-info/METADATA,sha256=2uXUL3bBbKANPJe9r5b3ARE4NoR_ixm1YfMdFnCSKHw,661
|
|
7
|
+
mvlogics-0.9.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
8
|
+
mvlogics-0.9.0.dist-info/top_level.txt,sha256=MEu4A_SLEh1sNkT89LhUa6Of2MzOCMowEKfFJjpeR_E,9
|
|
9
|
+
mvlogics-0.9.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jonathan Dung
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
mvlogics
|