Skip to content

rnel.operators

Priority-product operators (Sections 5.2, 6.2 and 8.3 of Smarandache and Leyva-Vázquez).

A tuple is a dict {component: value}. Conjunction multiplies every pair of components and assigns each product to the component of higher priority; components in the same tier share a product equally. Disjunction uses the reverse order and equals the De Morgan dual of conjunction.

Tuple = dict[str, float] module-attribute

TINF_AND = [['T'], ['N'], ['I'], ['F']] module-attribute

TINF_OR = [['F'], ['I'], ['N'], ['T']] module-attribute

priority_product(x, y, tiers)

Conjunction-type product with tiers ordered from lowest to highest priority.

Source code in src/rnel/operators.py
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
def priority_product(x: Mapping[str, float], y: Mapping[str, float], tiers: list[list[str]]) -> Tuple:
    """Conjunction-type product with tiers ordered from lowest to highest priority."""
    rank = {c: i for i, tier in enumerate(tiers) for c in tier}
    out = {c: 0.0 for c in rank}
    for a, xa in x.items():
        for b, yb in y.items():
            p = xa * yb
            if rank[a] != rank[b]:
                out[a if rank[a] > rank[b] else b] += p
            elif a == b:
                out[a] += p
            else:
                out[a] += p / 2
                out[b] += p / 2
    return out

mass(x)

Source code in src/rnel/operators.py
31
32
def mass(x: Mapping[str, float]) -> float:
    return sum(x.values())

tinf_not(x)

Negation kept from (T, I, N, F): (F, N, I, T).

Source code in src/rnel/operators.py
40
41
42
def tinf_not(x: Mapping[str, float]) -> Tuple:
    """Negation kept from (T, I, N, F): (F, N, I, T)."""
    return {"T": x["F"], "I": x["N"], "N": x["I"], "F": x["T"]}

tinf_and(x, y)

Source code in src/rnel/operators.py
45
46
def tinf_and(x, y) -> Tuple:
    return priority_product(x, y, TINF_AND)

tinf_or(x, y)

Source code in src/rnel/operators.py
49
50
def tinf_or(x, y) -> Tuple:
    return priority_product(x, y, TINF_OR)

mu_tiers(n, disjunction=False)

Source code in src/rnel/operators.py
54
55
56
def mu_tiers(n: int, disjunction: bool = False) -> list[list[str]]:
    t = [["T"], ["N"], [f"U{k}" for k in range(1, n + 1)], ["I"], ["F"]]
    return t[::-1] if disjunction else t

mu_not(x)

(T, I, N, U1..Un, F) -> (F, N, I, U1..Un, T).

Source code in src/rnel/operators.py
59
60
61
62
63
def mu_not(x: Mapping[str, float]) -> Tuple:
    """(T, I, N, U1..Un, F) -> (F, N, I, U1..Un, T)."""
    out = dict(x)
    out["T"], out["F"], out["I"], out["N"] = x["F"], x["T"], x["N"], x["I"]
    return out

mu_and(x, y)

Source code in src/rnel/operators.py
66
67
68
def mu_and(x, y) -> Tuple:
    n = sum(1 for k in x if k.startswith("U"))
    return priority_product(x, y, mu_tiers(n))

mu_or(x, y)

Source code in src/rnel/operators.py
71
72
73
def mu_or(x, y) -> Tuple:
    n = sum(1 for k in x if k.startswith("U"))
    return priority_product(x, y, mu_tiers(n, disjunction=True))

rnel_tiers(components, disjunction=False)

Source code in src/rnel/operators.py
77
78
79
80
def rnel_tiers(components: list[str], disjunction: bool = False) -> list[list[str]]:
    middle = [c for c in components if c not in ("T", "F")]
    t = [["T"], middle, ["F"]]
    return t[::-1] if disjunction else t

rnel_not(x)

Only T and F swap: contradiction, undetermined, neither and ignorance are fixed points (Belnap).

Source code in src/rnel/operators.py
83
84
85
86
87
def rnel_not(x: Mapping[str, float]) -> Tuple:
    """Only T and F swap: contradiction, undetermined, neither and ignorance are fixed points (Belnap)."""
    out = dict(x)
    out["T"], out["F"] = x["F"], x["T"]
    return out

rnel_and(x, y)

Source code in src/rnel/operators.py
90
91
def rnel_and(x, y) -> Tuple:
    return priority_product(x, y, rnel_tiers(list(x)))

rnel_or(x, y)

Source code in src/rnel/operators.py
94
95
def rnel_or(x, y) -> Tuple:
    return priority_product(x, y, rnel_tiers(list(x), disjunction=True))

implies(x, y, neg, disj)

x -> y := not x or y.

Source code in src/rnel/operators.py
 98
 99
100
def implies(x, y, neg, disj) -> Tuple:
    """x -> y := not x or y."""
    return disj(neg(x), y)

coarsen(x)

pi: (T, everything else, F) -> SL (b, u, d) coordinates, unnormalised.

Source code in src/rnel/operators.py
103
104
105
106
def coarsen(x: Mapping[str, float]) -> tuple[float, float, float]:
    """pi: (T, everything else, F) -> SL (b, u, d) coordinates, unnormalised."""
    rest = mass(x) - x["T"] - x["F"]
    return x["T"], rest, x["F"]

calibrated_and(x, y, ax, ay, conj=tinf_and)

Base-rate-calibrated conjunction: the priority-product conjunction conj (tinf_and, mu_and or rnel_and) plus the transfer K = [(1-ax) ay T_x I_y + ax (1-ay) I_x T_y] / (1 - ax ay) from indeterminacy to T, where I is the total indeterminacy mass. On normalised inputs its coarsening is SL multiplication with base rates ax, ay. The base rate of the result is ax * ay.

Source code in src/rnel/operators.py
128
129
130
131
132
133
134
135
136
137
138
def calibrated_and(x, y, ax: float, ay: float, conj=tinf_and) -> Tuple:
    """Base-rate-calibrated conjunction: the priority-product conjunction `conj` (tinf_and, mu_and or rnel_and)
    plus the transfer K = [(1-ax) ay T_x I_y + ax (1-ay) I_x T_y] / (1 - ax ay) from indeterminacy to T, where
    I is the total indeterminacy mass. On normalised inputs its coarsening is SL multiplication with base
    rates ax, ay. The base rate of the result is ax * ay."""
    z = conj(x, y)
    den = 1 - ax * ay
    if den <= 0:
        return z
    k = ((1 - ax) * ay * x["T"] * _indeterminacy(y) + ax * (1 - ay) * _indeterminacy(x) * y["T"]) / den
    return _transfer(z, k, "T")

calibrated_or(x, y, ax, ay, disj=tinf_or)

Base-rate-calibrated disjunction: disj plus the transfer K = [ax (1-ay) F_x I_y + (1-ax) ay I_x F_y] / (ax + ay - ax ay) from indeterminacy to F. On normalised inputs its coarsening is SL comultiplication with base rates ax, ay. The base rate of the result is ax + ay - ax * ay.

Source code in src/rnel/operators.py
141
142
143
144
145
146
147
148
149
150
151
def calibrated_or(x, y, ax: float, ay: float, disj=tinf_or) -> Tuple:
    """Base-rate-calibrated disjunction: `disj` plus the transfer
    K = [ax (1-ay) F_x I_y + (1-ax) ay I_x F_y] / (ax + ay - ax ay) from indeterminacy to F. On normalised
    inputs its coarsening is SL comultiplication with base rates ax, ay. The base rate of the result is
    ax + ay - ax * ay."""
    z = disj(x, y)
    den = ax + ay - ax * ay
    if den <= 0:
        return z
    k = (ax * (1 - ay) * x["F"] * _indeterminacy(y) + (1 - ax) * ay * _indeterminacy(x) * y["F"]) / den
    return _transfer(z, k, "F")