Basic Boolean Gates & T-Norm Semantics

This tutorial demonstrates how JLNN handles classical Boolean operations (AND, OR, NOT, NAND, NOR, XOR) using interval logic. You will see how crisp inputs (0/1) translate to certain intervals, how the system manages uncertainty, and how different logical semantics affect propagation.

Note

The interactive notebooks are hosted externally to ensure the best viewing experience and to allow immediate execution in the cloud.

Grid comparing the Classic and Multi-Semantics JLNN version 0.1.3

Classic Boolean Gates (Inference) in Colab

Basic Version: Learn the core syntax, manual crisp inputs, and the transfer of basic interval uncertainty without training.

https://colab.research.google.com/github/RadimKozl/JLNN/blob/main/examples/JLNN_basic_boolean_gates.ipynb
View Classic on GitHub

Browse the classic notebook source code and outputs directly in the GitHub viewer.

https://github.com/RadimKozl/JLNN/blob/main/examples/JLNN_basic_boolean_gates.ipynb
Advanced T-Norms & PFL Semantics (JLNN version 0.1.3)

Comprehensive Version: Compare how uncertainty propagates across multiple logic setups (lukasiewicz, godel, product) and entropic Physical Fuzzy Logic.

https://colab.research.google.com/github/RadimKozl/JLNN/blob/main/examples/JLNN_basic_boolean_gates2.ipynb
View Advanced JLNN version 0.1.3 on GitHub

Browse the multi-semantics notebook source code and advanced matrix visualizations on GitHub.

https://github.com/RadimKozl/JLNN/blob/main/examples/JLNN_basic_boolean_gates2.ipynb

Theoretical Overview of Semantics

When moving beyond basic logical evaluations, JLNN provides seamless switching between different fuzzy t-norms and space-curving fields:

  • Łukasiewicz Logic: Nilpotent linear approach (T(A, B) = max(0, A + B - 1)). Accumulates uncertainty linearly and provides rock-solid gradient properties.

  • Gödel Logic: Strict lattice mapping based on minimums (T(A, B) = min(A, B)). Conserves boundary extremes completely without compounding uncertainty.

  • Product Logic: Smooth multiplicative interpretation (T(A, B) = A … B). Generates smooth continuous polynomial propagation landscapes.

  • Physical Fuzzy Logic (PFL): Warps the underlying logical grid coordinate space based on local Shannon entropy, shielding deep rule-graphs from cascading uncertainty noise.

import os
import sys

'''
def setup_jlnn_custom_environment(backend: str = "gpu"):

    import os

    backend = backend.lower().strip()
    valid_backends = ["cpu", "gpu", "tpu"]
    if backend not in valid_backends:
        raise ValueError(f"Invalid backend '{backend}'. Choose one of: {valid_backends}")

    print(f"🧹 Cleaning the environment and installing JLNN for backend: {backend.upper()}...")

    # We will only uninstall any old versions of Jax from Colab to avoid driver conflicts
    !pip uninstall -y jax jaxlib --quiet

    # Installation using our newly prepared production packages
    if backend == "gpu":
        print("🔥 Installing JAX & JLNN with official CUDA 12+ GPU support...")
        # Uses jax[cuda12] and the export pipeline without pulling the entire TF
        !pip install "jax-lnn[gpu,export]" --quiet
    elif backend == "tpu":
        print("🚀 Installing JAX & JLNN with TPU support...")
        !pip install "jax-lnn[tpu,export]" --quiet
    else:
        print("💻 Installing JAX & JLNN for pure CPU calculations...")
        !pip install "jax-lnn[cpu,export]" --quiet

    # We will only install specific add-ons for this particular nanoGPT laptop
    print("📊 Installing additional data and NLP tools for nanoGPT...")
    !pip install pandas polars matplotlib seaborn --quiet


    print("\n🔄 RESTARTING COLAB SESSION to apply hardware changes to Python...")
    print("💡 Please note: If your browser disconnects, just wait 5 seconds and click 'Reconnect'.")

    # Graceful restart via UI in Colab is recommended, but if automatic repair is running,
    # os.kill is required to load new JAX C++ libraries into memory.
    os.kill(os.getpid(), 9)
'''

REQUIRED_BACKEND = "cpu"

try:
    import jax
    import jlnn
    import os

    if REQUIRED_BACKEND == "tpu" and 'TPU_NAME' in os.environ:
        import jax.tools.colab_tpu
        jax.tools.colab_tpu.setup_tpu()

    current_platform = jax.devices()[0].platform.lower()

    if REQUIRED_BACKEND == "gpu" and current_platform == "cpu":
        raise RuntimeError("JAX only sees the CPU, even if you demand full GPU power with CUDA 12!")

    if REQUIRED_BACKEND == "tpu" and current_platform == "cpu":
        raise RuntimeError("JAX fell into CPU mode, failed to map TPU correctly!")

    print(f"✅ The jax-lnn environment is successfully configured.")
    print(f"✅ Active hardware backend: {current_platform.upper()}")
    print(f"✅ Confirmed detected devices: {jax.devices()}")

except (ImportError, RuntimeError) as e:
    print(f"⚠️ Environment does not meet specification ({str(e)}). Running automatic repair...")
    setup_jlnn_custom_environment(backend=REQUIRED_BACKEND)

'''
!pip show jax-lnn

!rm -rf /content/sample_data
'''

# Imports

import jlnn
import jax.numpy as jnp
from flax import nnx
import jax
import matplotlib.pyplot as plt

# JLNN core imports (Updated for v013 backend verification)
from jlnn.nn.gates import WeightedAnd, WeightedOr, WeightedNot, WeightedNand, WeightedNor, WeightedXor
from jlnn.nn.gates import PhysicalAnd, PhysicalOr, PhysicalNot, PhysicalNand, PhysicalNor
from jlnn.nn.predicates import FixedPredicate
from jlnn.symbolic.compiler import LNNFormula

print("JLNN loaded with advanced T-norm and PFL support.")

# 2. Common inputs for experiments (batch size 1)

crisp_inputs = {
    "A": jnp.array([[1.0, 1.0]]),   # A = True
    "B": jnp.array([[0.0, 0.0]])    # B = False
}

fuzzy_inputs = {
    "A": jnp.array([[0.95, 1.0]]),  # A almost True
    "B": jnp.array([[0.05, 0.1]])   # B almost False
}

# Dynamic Gate Runner with Method Switching

def run_gate_with_method(rule, inputs, method='lukasiewicz'):
    """
    Runs a formula graph and dynamically injects either traditional parametric
    or physical fuzzy logic components using safe Flax NNX traversal.
    """
    model = LNNFormula(rule, nnx.Rngs(42))

    # 1. Override predicates to Fixed (identity) identity transformations
    for name in inputs:
        if name in model.predicates:
            model.predicates[name].predicate = FixedPredicate()

    # 2. Dynamic module transmutation depending on target semantics
    # We use nnx.iter_modules() to fix the DeprecationWarning
    for path, module in nnx.iter_modules(model):
        # Identify Node references that wrap a gate component
        if hasattr(module, 'gate'):
            current_gate = module.gate

            if method.startswith('physical_'):
                # Transmute traditional parametric gates to Physical (PFL) equivalents
                if isinstance(current_gate, WeightedAnd):
                    module.gate = PhysicalAnd(method=method)
                elif isinstance(current_gate, WeightedOr):
                    module.gate = PhysicalOr(method=method)
                elif isinstance(current_gate, WeightedNot):
                    module.gate = PhysicalNot()
                elif isinstance(current_gate, WeightedNand):
                    module.gate = PhysicalNand(method=method)
                elif isinstance(current_gate, WeightedNor):
                    module.gate = PhysicalNor(method=method)
                elif isinstance(current_gate, WeightedXor):
                    # For complex compounds like XOR under PFL, we configure fallback semantic execution
                    if hasattr(current_gate, 'method'):
                        current_gate.method = 'lukasiewicz' # Parametric routing fallback for XOR
            else:
                # Standard parametric setup
                if hasattr(current_gate, 'method'):
                    current_gate.method = method

    # 3. Secure forward evaluation
    output = model(inputs)

    # 4. Extract metrics
    output = jnp.sort(output, axis=-1)
    L = output[0, 0].item()
    U = output[0, 1].item()
    width = U - L

    return L, U, width

# 3. AND Semantics Comparison

methods_to_test = ['lukasiewicz', 'godel', 'product', 'physical_kleene_dienes']

print("=== AND Semantics ===")

for m in methods_to_test:
    _, _, w_c = run_gate_with_method("A & B", crisp_inputs, method=m)
    _, _, w_f = run_gate_with_method("A & B", fuzzy_inputs, method=m)
    print(f"Method: {m:<25} -> Crisp Width: {w_c:.4f}, Fuzzy Width: {w_f:.4f}")

# 4. OR Semantics Comparison

print("\n=== OR Semantics ===")

for m in methods_to_test:
    _, _, w_c = run_gate_with_method("A | B", crisp_inputs, method=m)
    _, _, w_f = run_gate_with_method("A | B", fuzzy_inputs, method=m)
    print(f"Method: {m:<25} -> Crisp Width: {w_c:.4f}, Fuzzy Width: {w_f:.4f}")

# 5. XOR Uncertainty Singularity

print("\n=== XOR Semantics ===")

for m in methods_to_test:
    _, _, w_c = run_gate_with_method("(A & ~B) | (~A & B)", crisp_inputs, method=m)
    _, _, w_f = run_gate_with_method("(A & ~B) | (~A & B)", fuzzy_inputs, method=m)
    print(f"Method: {m:<25} -> Crisp Width: {w_c:.4f}, Fuzzy Width: {w_f:.4f}")

# 6. Visualizing the uncertainty matrix with multiple semantics

gates = ["AND", "OR", "XOR"]
methods = ['lukasiewicz', 'godel', 'product', 'physical_kleene_dienes']
results = {m: [] for m in methods}

for gate in gates:
    if gate == "AND":
        rule = "A & B"
    elif gate == "OR":
        rule = "A | B"
    elif gate == "XOR":
        rule = "(A & ~B) | (~A & B)"

    for m in methods:
        _, _, w_fuzzy = run_gate_with_method(rule, fuzzy_inputs, method=m)
        results[m].append(w_fuzzy)

# 7. Plotting the multi-bar chart

x = jnp.arange(len(gates))
width = 0.2
fig, ax = plt.subplots(figsize=(10, 6))

for i, m in enumerate(methods):
    ax.bar(x + (i * width) - (len(methods)*width/2) + width/2,
        results[m], width, label=m)

ax.set_xticks(x)
ax.set_xticklabels(gates)
ax.set_ylabel('Output Uncertainty Width (U - L)')
ax.set_title('v013 Update: Uncertainty Propagation Across Different Logical Semantics')
ax.legend()
plt.grid(axis='y', linestyle='--', alpha=0.5)
plt.tight_layout()
plt.show()

Download

You can also download the raw notebook file for local use: JLNN_basic_boolean_gates2.ipynb

Tip

To run the notebook locally, make sure you have installed the package using pip install -e .[test].