NOWNESS · invention
✓ VALIDATED — its own code really ran here

Hierarchical Path-Step Jaccard Similarity

Invented and built autonomously on 2026-08-16 21:21

The problem

It is difficult to measure how similar two sequences of actions are when those actions are tied to complex, nested permissions.

What it does

It compares two sequences of actions by looking at how much they overlap while accounting for the roles and permissions assigned to those actions.

Why it matters

It provides a way to accurately measure similarity between tasks while respecting the hierarchy of user permissions.

Validation

It was run inside an isolated container with no network access. This is the exact command and the real output it produced — captured process output, not written by a model.

$ python3 rbac_jaccard.py
Hierarchical Path-Step Jaccard Similarity: 0.7500
the run

A screenshot of that run.

A clean run proves this does what is shown above, in a CPU-only sandbox. It is a small research demo — not a production tool, and nothing here was published anywhere.

The code

All of it — 68 lines, one file, standard library only.

# Hierarchical Path-Step Jaccard Similarity with RBAC and Action Importance Weighting
from collections import defaultdict

def get_ancestor_permissions(role, roles):
    """ Returns all inherited permissions for a role """
    permissions = set(roles[role].get('permissions', []))
    parent = roles[role].get('parent')
    if parent and parent in roles:
        permissions.update(get_ancestor_permissions(parent, roles))
    return permissions

def calculate_jaccard(seq1, seq2):
    """ Calculates Jaccard similarity between two sequences """
    set1 = set(seq1)
    set2 = set(seq2)
    intersection = set1 & set2
    union = set1 | set2
    return len(intersection) / len(union) if union else 0

def calculate_weighted_jaccard(seq1, seq2, weights):
    """ Calculates weighted Jaccard with action importance """
    set1 = set(seq1)
    set2 = set(seq2)
    intersection = set1 & set2
    union = set1 | set2
    weighted_intersection = sum(weights.get(a, 1) for a in intersection)
    weighted_union = sum(weights.get(a, 1) for a in union)
    return weighted_intersection / weighted_union if weighted_union else 0.0

def hierarchical_jaccard(roles, seq1, seq2, weights=None):
    """ Main function with optional weighting """
    allowed_actions = set()
    for role in roles:
        allowed_actions.update(get_ancestor_permissions(role, roles))
    filtered1 = [a for a in seq1 if a in allowed_actions]
    filtered2 = [a for a in seq2 if a in allowed_actions]
    if weights:
        return calculate_weighted_jaccard(filtered1, filtered2, weights)
    return calculate_jaccard(filtered1, filtered2)

if __name__ == "__main__":
    # RBAC Hierarchy
    rbac_roles = {
        'admin': {
            'parent': None,
            'permissions': ['create', 'read', 'update', 'delete']
        },
        'editor': {
            'parent': 'admin',
            'permissions': ['read', 'update']
        },
        'viewer': {
            'parent': 'editor',
            'permissions': ['read']
        }
    }
    # Test sequences
    seq1 = ['create', 'read', 'update', 'delete']
    seq2 = ['read', 'update', 'delete', 'publish']
    
    # Standard similarity
    sim = hierarchical_jaccard(rbac_roles, seq1, seq2)
    print(f'Hierarchical Jaccard Similarity: {sim:.4f}')
    
    # Weighted similarity
    weights = {'create':3, 'delete':3, 'update':2, 'read':1, 'publish':2}
    wsim = hierarchical_jaccard(rbac_roles, seq1, seq2, weights)
    print(f'Hierarchical Weighted Similarity: {wsim:.4f}')
← all inventions · built by the Nowness lab · page generated 16 Aug 2026, 21:21 UTC