# Copyright (c) 2026 Andrew H. Bond
# Department of Computer Engineering, San Jose State University
# Licensed under the AGI-HPC Responsible AI License v1.0.

"""
hohfeld_d4_demo.py

Demonstration of D4 Dihedral Group Structure for Hohfeldian Normative Positions.

This demo illustrates the mathematical structure underlying moral reasoning:
- The four Hohfeldian positions: Obligation (O), Claim (C), Liberty (L), No-claim (N)
- The D4 group (symmetries of a square) acting on these positions
- Correlative symmetry (s): perspective swap between parties
- Negation symmetry (r²): logical negation of normative status
- Non-abelian structure: order of operations matters (rs ≠ sr)

Usage:
    python -m erisml.examples.hohfeld_d4_demo

References:
    Hohfeld, W.N. (1917). "Fundamental Legal Conceptions as Applied in
    Judicial Reasoning." Yale Law Journal, 26(8), 710-770.

    Bond, A.H. & Claude (2026). "SQND-Probe: A Gamified Instrument for
    Measuring Dihedral Gauge Structure in Human Moral Reasoning."
"""

from __future__ import annotations

from erisml.ethics.hohfeld import (
    HohfeldianState,
    D4Element,
    SemanticGate,
    HohfeldianVerdict,
    d4_multiply,
    d4_apply_to_state,
    correlative,
    negation,
    apply_semantic_gate,
    compute_bond_index,
    compute_wilson_observable,
    get_klein_four_subgroup,
    is_in_klein_four,
    requires_nonabelian_structure,
)


def print_section(title: str) -> None:
    """Print a section header."""
    print()
    print("=" * 70)
    print(f"  {title}")
    print("=" * 70)


def demo_hohfeldian_positions() -> None:
    """Demonstrate the four Hohfeldian normative positions."""
    print_section("The Four Hohfeldian Normative Positions")

    print(
        """
The Hohfeldian square arranges four fundamental normative positions:

         O (Obligation) -------- C (Claim)
              |                      |
              |                      |
         L (Liberty) ---------- N (No-claim)

Correlative pairs (perspective swap):
  - O <-> C: If A is obligated to B, then B has a claim against A
  - L <-> N: If A is at liberty against B, then B has no-claim against A

Negation pairs (logical opposites):
  - O <-> L: Obligation vs Liberty
  - C <-> N: Claim vs No-claim
"""
    )

    print("States:", [s.value for s in HohfeldianState])


def demo_d4_group() -> None:
    """Demonstrate the D4 dihedral group."""
    print_section("The D4 Dihedral Group (Symmetries of a Square)")

    print(
        """
D4 has 8 elements generated by:
  - r: 90 degree clockwise rotation (O -> C -> L -> N -> O)
  - s: reflection/correlative (O <-> C, L <-> N)

The elements are:
"""
    )
    for elem in D4Element:
        print(f"  {elem.value:4s} - {_element_description(elem)}")

    print("\nDefining relations:")
    print("  - r^4 = e (four rotations return to identity)")
    print("  - s^2 = e (reflection is self-inverse)")
    print("  - srs = r^-1 (the key non-abelian relation)")


def _element_description(elem: D4Element) -> str:
    """Get description for a D4 element."""
    descriptions = {
        D4Element.E: "Identity",
        D4Element.R: "90 degree rotation",
        D4Element.R2: "180 degree rotation (negation)",
        D4Element.R3: "270 degree rotation (= r inverse)",
        D4Element.S: "Reflection (correlative)",
        D4Element.SR: "s composed with r",
        D4Element.SR2: "s composed with r^2",
        D4Element.SR3: "s composed with r^3",
    }
    return descriptions.get(elem, "Unknown")


def demo_correlative_symmetry() -> None:
    """Demonstrate correlative symmetry (s-reflection)."""
    print_section("Correlative Symmetry (Perspective Swap)")

    print("The correlative operation swaps perspectives between parties:\n")

    for state in HohfeldianState:
        corr = correlative(state)
        print(f"  correlative({state.value}) = {corr.value}")

    print(
        """
Example: Alice lends money to Bob
  - Alice's perspective: Bob has OBLIGATION to repay (O)
  - Bob's perspective: Alice has CLAIM to receive payment (C)

The correlative symmetry captures this: correlative(O) = C
"""
    )


def demo_negation_symmetry() -> None:
    """Demonstrate negation symmetry (r^2)."""
    print_section("Negation Symmetry (Logical Opposites)")

    print("The negation operation (r^2) maps to logical opposites:\n")

    for state in HohfeldianState:
        neg = negation(state)
        print(f"  negation({state.value}) = {neg.value}")

    print(
        """
Example: "You must do X" vs "You may refuse X"
  - "Must" implies OBLIGATION (O)
  - "May refuse" implies LIBERTY (L)

These are logical negations: negation(O) = L
"""
    )


def demo_nonabelian_structure() -> None:
    """Demonstrate non-abelian structure (rs != sr)."""
    print_section("Non-Abelian Structure (Order Matters)")

    r = D4Element.R
    s = D4Element.S

    rs = d4_multiply(r, s)
    sr = d4_multiply(s, r)

    print(f"r * s = {rs.value}")
    print(f"s * r = {sr.value}")
    print(f"\nrs != sr: {rs != sr}")

    print("\nApplying to states shows the path dependence:")
    for state in HohfeldianState:
        # Path 1: rotate then swap
        via_rs = d4_apply_to_state(s, d4_apply_to_state(r, state))
        # Path 2: swap then rotate
        via_sr = d4_apply_to_state(r, d4_apply_to_state(s, state))

        print(
            f"  {state.value}: r then s -> {via_rs.value}, s then r -> {via_sr.value}"
        )

    print(
        """
This non-commutativity is the signature of D4's non-abelian structure.
It means the ORDER of moral reasoning operations can affect the outcome.
"""
    )


def demo_semantic_gates() -> None:
    """Demonstrate semantic gates (linguistic triggers)."""
    print_section("Semantic Gates (Linguistic Triggers)")

    print("Semantic gates are phrases that trigger D4 transformations:\n")

    examples = [
        (SemanticGate.ONLY_IF_CONVENIENT, HohfeldianState.O),
        (SemanticGate.I_PROMISE, HohfeldianState.L),
        (SemanticGate.FROM_THEIR_PERSPECTIVE, HohfeldianState.O),
    ]

    for gate, initial in examples:
        final = apply_semantic_gate(gate, initial)
        print(f'  "{gate.value}" applied to {initial.value} -> {final.value}')

    print(
        """
Example: "Please help me with this task, but only if convenient."
  - Base state: O (Obligation to help)
  - Gate: "only if convenient" (negation, r^2)
  - Result: L (Liberty - free to refuse)
"""
    )


def demo_bond_index() -> None:
    """Demonstrate bond index computation."""
    print_section("Bond Index (Correlative Symmetry Measure)")

    print(
        """
The bond index measures deviation from correlative symmetry.
It quantifies how consistently a reasoner applies perspective swaps.
"""
    )

    # Perfect symmetry case
    verdicts_a = [
        HohfeldianVerdict("A", HohfeldianState.O),
        HohfeldianVerdict("A", HohfeldianState.L),
        HohfeldianVerdict("A", HohfeldianState.C),
    ]
    verdicts_b_perfect = [
        HohfeldianVerdict("B", HohfeldianState.C),  # correlative(O) = C
        HohfeldianVerdict("B", HohfeldianState.N),  # correlative(L) = N
        HohfeldianVerdict("B", HohfeldianState.O),  # correlative(C) = O
    ]

    bi_perfect = compute_bond_index(verdicts_a, verdicts_b_perfect)
    print(f"Perfect correlative symmetry: Bond Index = {bi_perfect:.3f}")

    # Imperfect symmetry case
    verdicts_b_imperfect = [
        HohfeldianVerdict("B", HohfeldianState.C),  # correct
        HohfeldianVerdict("B", HohfeldianState.L),  # WRONG - should be N
        HohfeldianVerdict("B", HohfeldianState.O),  # correct
    ]

    bi_imperfect = compute_bond_index(verdicts_a, verdicts_b_imperfect)
    print(f"One violation (1/3 wrong): Bond Index = {bi_imperfect:.3f}")

    print(
        """
Interpretation:
  - Bond Index = 0: Perfect correlative symmetry
  - Bond Index > 0: Systematic asymmetry in moral reasoning
"""
    )


def demo_wilson_observable() -> None:
    """Demonstrate Wilson observable computation."""
    print_section("Wilson Observable (Path Holonomy)")

    print(
        """
The Wilson observable measures whether a closed path of transformations
returns to the predicted state (holonomy computation).
"""
    )

    # Test srs = r^-1 relation
    path_srs = [D4Element.S, D4Element.R, D4Element.S]
    path_r3 = [D4Element.R3]

    for initial in [HohfeldianState.O]:
        # srs path
        final_srs = initial
        for g in path_srs:
            final_srs = d4_apply_to_state(g, final_srs)

        # r^3 path
        final_r3 = d4_apply_to_state(D4Element.R3, initial)

        holonomy_srs, matched_srs = compute_wilson_observable(
            path_srs, initial, final_srs
        )
        holonomy_r3, matched_r3 = compute_wilson_observable(path_r3, initial, final_r3)

        print(f"Starting from {initial.value}:")
        print(
            f"  Path srs: {initial.value} -> {final_srs.value}, holonomy={holonomy_srs.value}, matched={matched_srs}"
        )
        print(
            f"  Path r^3: {initial.value} -> {final_r3.value}, holonomy={holonomy_r3.value}, matched={matched_r3}"
        )

    print(
        """
The srs = r^-1 relation means both paths produce the same final state.
This is a key verification of the D4 group structure.
"""
    )


def demo_klein_four_subgroup() -> None:
    """Demonstrate the Klein four abelian subgroup."""
    print_section("Klein Four Subgroup (Abelian Core)")

    print("The Klein four-group V4 = {e, r^2, s, sr^2} is an abelian subgroup:")
    print()

    subgroup = get_klein_four_subgroup()
    for elem in subgroup:
        in_v4 = is_in_klein_four(elem)
        print(f"  {elem.value:4s} in V4: {in_v4}")

    print(
        """
If only operations from V4 are empirically observed (negation + correlative),
we have NOT demonstrated the full non-abelian D4 structure.

To prove non-abelian structure, we need 'quarter-turn' elements:
"""
    )
    non_abelian = [D4Element.R, D4Element.R3, D4Element.SR, D4Element.SR3]
    for elem in non_abelian:
        print(f"  {elem.value}")

    # Check if a set of operations requires non-abelian structure
    ops_abelian = [D4Element.R2, D4Element.S, D4Element.SR2]
    ops_nonabelian = [D4Element.R, D4Element.S]

    print(
        f"\nOperations {[e.value for e in ops_abelian]} require non-abelian: "
        f"{requires_nonabelian_structure(ops_abelian)}"
    )
    print(
        f"Operations {[e.value for e in ops_nonabelian]} require non-abelian: "
        f"{requires_nonabelian_structure(ops_nonabelian)}"
    )


def main() -> None:
    """Run all demonstrations."""
    print("\n" + "=" * 70)
    print("  D4 HOHFELDIAN GAUGE STRUCTURE DEMONSTRATION")
    print("=" * 70)

    demo_hohfeldian_positions()
    demo_d4_group()
    demo_correlative_symmetry()
    demo_negation_symmetry()
    demo_nonabelian_structure()
    demo_semantic_gates()
    demo_bond_index()
    demo_wilson_observable()
    demo_klein_four_subgroup()

    print_section("Summary")
    print(
        """
The D4 dihedral group provides a rigorous mathematical framework for
understanding symmetries in moral reasoning:

1. CORRELATIVE SYMMETRY (s): Perspective swaps preserve moral structure
2. NEGATION SYMMETRY (r^2): Logical opposites form consistent pairs
3. NON-ABELIAN STRUCTURE: Order of operations can matter
4. BOND INDEX: Measures deviation from expected symmetry
5. WILSON OBSERVABLE: Verifies path-independence of group structure

This framework enables empirical testing of moral reasoning patterns
and identification of systematic biases in ethical decision-making.
"""
    )


if __name__ == "__main__":
    main()
