Nabil Aouf

139 papers A* 5A 2B 10C 10Journal 58Unranked 54
YearRankTypeTitle / Venue / Authors
2025 J jnl
CoRR
Thomas Hickling, Maxwell Hogan, Abdulla Tammam, Nabil Aouf
2025 J jnl
IEEE Trans. Intell. Veh.
Chuyao Wang, Nabil Aouf
2025 B conf
SMC
Abdulla Tammam, Nabil Aouf
2025 J jnl
IEEE Trans. Aerosp. Electron. Syst.
Jianing Song, Nabil Aouf, Duarte Rondao, Christophe Honvault, Luis Mansilla, Qingxiang Yang
2024 J jnl
Adv. Intell. Syst.
Mahmoud Abdulsalam, Kenan Ahiska, Nabil Aouf
2024 conf
ICARA
Zuyuan Zhu, Zakaria Chekakta, Nabil Aouf
2024 J jnl
J. Intell. Robotic Syst.
Chuyao Wang, Nabil Aouf
2024 conf
CASE
Zakaria Chekakta, Abdelhafid Zenati, Nabil Aouf
2024 J jnl
ACM Comput. Surv.
Thomas Hickling, Abdelhafid Zenati, Nabil Aouf, Phillippa Spencer
2024 J jnl
CoRR
Jianing Song, Nabil Aouf, Duarte Rondao, Christophe Honvault, Luis Mansilla
2024 conf
ROBIO
Maxwell Hogan, Youngseob Dae, Chuyao Wang, Nabil Aouf
2024 conf
ICCMA
Alaa Afaneh, Nabil Aouf
2024 J jnl
IEEE Trans. Intell. Veh.
Hugo Courtois, Nabil Aouf, Kenan Ahiska, Marco Cecotti
2024 conf
ROBIO
Thomas Hickling, Nabil Aouf
2024 conf
ICARA
Zakaria Chekakta, Nabil Aouf, Shashank Govindaraj, Fabio Polisano, Geert De Cubber
2024 conf
ROBIO
Burak Alp Inan, Nabil Aouf
2023 J jnl
IEEE Trans. Aerosp. Electron. Syst.
Duarte Rondao, Nabil Aouf, Mark A. Richardson
2023 conf
MED
Burak Alp Inan, Duarte Rondao, Nabil Aouf
2023 conf
MED
Mahmoud Abdulsalam, Zakaria Chekakta, Nabil Aouf, Maxwell Hogan
2023 conf
ROBIO
Burak Alp Inan, Duarte Rondao, Nabil Aouf
2023 J jnl
IEEE Trans. Autom. Control.
Abdelhafid Zenati, Nabil Aouf, Mohamed Tadjine, Taous-Meriem Laleg-Kirati
2023 J jnl
CoRR
Duarte Rondao, Lei He, Nabil Aouf
2023 J jnl
IEEE Trans. Intell. Veh.
Thomas Hickling, Nabil Aouf, Phillippa Spencer
2023 J jnl
CoRR
Ziwei Wang, Nabil Aouf, Jose Pizarro, Christophe Honvault
2023 conf
ROBIO
Amar Ali N. Khan, Nabil Aouf
2023 J jnl
CoRR
Mahmoud Abdulsalam, Nabil Aouf
2023 conf
ROBIO
Mahmoud Abdulsalam, Nabil Aouf
2022 C conf
ACC
Abdelhafid Zenati, Nabil Aouf, Odysseas Kechagias-Stamatis
2022 J jnl
CoRR
Thomas Hickling, Abdelhafid Zenati, Nabil Aouf, Phillippa Spencer
2022 conf
ICARSC
Maxwell Hogan, Nabil Aouf, Phillippa Spencer, Jay Almond
2022 C conf
IV
Chuyao Wang, Nabil Aouf
2022 J jnl
IEEE Trans. Hum. Mach. Syst.
Hugo Courtois, Nabil Aouf, Kenan Ahiska, Marco Cecotti
2022 J jnl
CoRR
Thomas Hickling, Nabil Aouf, Phillippa Spencer
2022 J jnl
IEEE Trans. Intell. Transp. Syst.
Axel Beauvisage, Kenan Ahiska, Nabil Aouf
2022 J jnl
CoRR
Abdelhafid Zenati, Nabil Aouf, David Sanchez de la Llana, Samir Bannani
2021 J jnl
CoRR
Abdenour Amamra, Nabil Aouf, Dowling Stuart, Mark A. Richardson
2021 A* conf
ICRA
Masoud Sotoodeh-Bahraini, Abdelhafid Zenati, Nabil Aouf
2021 J jnl
CoRR
Duarte Rondao, Nabil Aouf, Mark A. Richardson
2021 J jnl
CoRR
Jianing Song, Duarte Rondao, Nabil Aouf
2021 J jnl
IEEE Trans. Aerosp. Electron. Syst.
Carole Belloni, Alessio Balleri, Nabil Aouf, Jean-Marc Le Caillec, Thomas Merlet
2021 J jnl
CoRR
Abdenour Amamra, Tarek Mouats, Nabil Aouf
2021 J jnl
CoRR
Abdenour Amamra, Nabil Aouf
2021 conf
ROBIO
Abdelhafid Zenati, Nabil Aouf
2021 conf
ROBIO
Maxwell Hogan, Nabil Aouf
2021 J jnl
CoRR
Maxwell Hogan, Duarte Rondao, Nabil Aouf, Olivier Dubois-Matra
2020 J jnl
IEEE Trans. Cogn. Dev. Syst.
Hamid Isakhani, Nabil Aouf, Odysseas Kechagias-Stamatis, James F. Whidborne
2020 J jnl
CoRR
Lei He, Nabil Aouf, James F. Whidborne, Bifeng Song
2020 conf
MED
Mahmoud Abdulsalam, Nabil Aouf
2020 J jnl
J. Field Robotics
Odysseas Kechagias-Stamatis, Nabil Aouf, Vincent Dubanchet
2020 J jnl
CoRR
Lei He, Nabil Aouf, Bifeng Song
2020 A* conf
ICRA
Lei He, Nabil Aouf, James F. Whidborne, Bifeng Song
2020 A* conf
ICRA
Axel Beauvisage, Kenan Ahiska, Nabil Aouf
2020 J jnl
IET Image Process.
Odysseas Kechagias-Stamatis, Nabil Aouf, Mark A. Richardson
2020 J jnl
CoRR
Duarte Rondao, Nabil Aouf, Mark A. Richardson, Vincent Dubanchet
2019 J jnl
IEEE Trans. Geosci. Remote. Sens.
Odysseas Kechagias-Stamatis, Nabil Aouf
2019 conf
ITSC
Marco Cecotti, Husain Kanchwala, Nabil Aouf
2019 conf
ICCVE
Icaro Bezerra Viana, Husain Kanchwala, Nabil Aouf
2019 J jnl
IEEE Trans. Aerosp. Electron. Syst.
Odysseas Kechagias-Stamatis, Nabil Aouf
2019 conf
ITSC
Husain Kanchwala, Icaro Bezerra Viana, Marco Cecotti, Nabil Aouf
2019 J jnl
J. Real Time Image Process.
Lounis Chermak, Nabil Aouf, Mark A. Richardson, Gianfranco Visentin
2019 J jnl
CoRR
Odysseas Kechagias-Stamatis, Nabil Aouf, Mark A. Richardson
2018 conf
IEEE Conf. on Intelligent Systems
Icaro Bezerra Viana, Nabil Aouf
2018 J jnl
J. Real Time Image Process.
Abdenour Amamra, Nabil Aouf
2018 J jnl
J. Intell. Robotic Syst.
Tarek Mouats, Nabil Aouf, David Nam, Stephen Vidas
2017 B conf
Intelligent Vehicles Symposium
David Nam, Nabil Aouf
2017 conf
ICNSC
Odysseas Kechagias-Stamatis, Nabil Aouf, Lounis Chermak
2017 J jnl
IEEE Trans. Intell. Veh.
Tankut Acarman, Matt Barth, Matthias Althoff, Nabil Aouf, Andreas A. Malikopoulos
2017 conf
IEEE SENSORS
Axel Beauvisage, Nabil Aouf
2017 conf
ECMR
Axel Beauvisage, Nabil Aouf
2017 conf
ICINCO (1)
José Alejandro Dena Ruiz, Nabil Aouf
2017 J jnl
Robotica
Lounis Chermak, Nabil Aouf, Mark A. Richardson
2017 conf
ICNSC
Zygfryd Wieszok, Nabil Aouf, Odysseas Kechagias-Stamatis, Lounis Chermak
2017 conf
ICINCO (2)
José Alejandro Dena Ruiz, Nabil Aouf
2017 J jnl
J. Intell. Robotic Syst.
Oualid Araar, Nabil Aouf, Ivan Vitanov
2016 J jnl
IEEE Trans. Aerosp. Electron. Syst.
Odysseas Kechagias-Stamatis, Nabil Aouf, Mark A. Richardson
2016 J jnl
Signal Image Video Process.
Abdenour Amamra, Nabil Aouf, Dowling Stuart, Mark A. Richardson
2016 J jnl
J. Vis. Commun. Image Represent.
Riad Azzam, Mohamed Sadek Kemouche, Nabil Aouf, Mark A. Richardson
2016 conf
CEEC
Louis-Pierre Bergé, Nabil Aouf, Thierry Duval, Gilles Coppin
2016 A* conf
ICRA
Odysseas Kechagias-Stamatis, Nabil Aouf
2016 B conf
SMC
Axel Beauvisage, Nabil Aouf, Hugo Courtois
2016 J jnl
Robotica
Abdenour Amamra, Nabil Aouf
2016 J jnl
Robotica
Mohammed Boulekchour, Nabil Aouf, Mark A. Richardson
2016 conf
IHM
Louis-Pierre Bergé, Thierry Duval, Nabil Aouf, Gilles Coppin
2015 J jnl
IEEE Trans. Image Process.
Tarek Mouats, Nabil Aouf, Mark A. Richardson
2015 conf
ICDP
Kemouche Abdennour, Nabil Aouf
2015 conf
MED
Odysseas Kechagias-Stamatis, Nabil Aouf
2015 J jnl
IEEE Trans. Intell. Transp. Syst.
Tarek Mouats, Nabil Aouf, Angel Domingo Sappa, Cristhian A. Aguilera-Carrasco, Ricardo Toledo
2015 J jnl
Ind. Robot
Oualid Araar, Nabil Aouf, Jose Luis Vallejo Dietz
2014 conf
MED
Oualid Araar, Nabil Aouf
2014 J jnl
Int. J. Appl. Pattern Recognit.
Xiaodong Li, Nabil Aouf, Mark A. Richardson
2014 A conf
IROS
Mohammed Boulekchour, Nabil Aouf
2014 conf
MED
Ivan Vitanov, Nabil Aouf
2014 conf
AHS
Ivan Vitanov, Nabil Aouf
2014 conf
ICCA
Saif H. Almutairi, Nabil Aouf
2014 J jnl
Kybernetes
Lounis Chermak, Nabil Aouf, Mark A. Richardson
2014 conf
MED
Mohammed Boulekchour, Nabil Aouf
2014 conf
SOSE
Badis Djamaa, Mark A. Richardson, Nabil Aouf, Bob Walters
2014 J jnl
Wirel. Networks
Badis Djamaa, Mark A. Richardson, Nabil Aouf, Bob Walters
2014 conf
CSNDSP
Badis Djamaa, Mark A. Richardson, Nabil Aouf, Bob Walters
2014 conf
MED
Oualid Araar, Nabil Aouf
2013 B conf
SMC
Saad Ali Imran, Nabil Aouf
2013 B conf
SMC
Riad Azzam, Nabil Aouf
2013 conf
ROBIO
Saad Ali Imran, Nabil Aouf
2013 B conf
SMC
Tarek Mouats, Nabil Aouf
2013 conf
ICEAC
Badis Djamaa, Nabil Aouf, Mark A. Richardson, Bob Walters
2013 conf
CICSyN
Xiaodong Li, Nabil Aouf
2013 A* conf
ICRA
Steven J. Mills, Nabil Aouf, Luis Mejías
2013 conf
CAIP (2)
Mohammed Boulekchour, Nabil Aouf
2013 C conf
FUSION
Tarek Mouats, Nabil Aouf
2013 conf
ROBIO
Saad Ali Imran, Nabil Aouf, Mark A. Richardson
2013 B conf
SMC
Abdenour Amamra, Nabil Aouf
2013 C conf
IV
Abdenour Amamra, Nabil Aouf
2013 conf
ICDP
Riad Azzam, Nabil Aouf
2013 B conf
SMC
Oualid Araar, Nabil Aouf
2012 conf
ROBIO
Xiaodong Li, Nabil Aouf
2012 conf
MFI
Xiaodong Li, Nabil Aouf, Abdelkrim Nemra
2012 conf
ROCOND
Abdelkrim Nemra, Nabil Aouf
2012 J jnl
J. Electronic Imaging
Saad Ali Imran, Nabil Aouf
2012 conf
MFI
Diego Rodriguez, Nabil Aouf
2011 conf
TAROS
Saad Ali Imran, Nabil Aouf
2011 J jnl
Signal Image Video Process.
Mohd. Kharbat, Nabil Aouf
2010 C conf
FUSION
Mohamed Sadek Kemouche, Nabil Aouf
2010 conf
ICINCO (2)
M. A. Shah, Antonios Tsourdos, Peter M. G. Silson, D. James, Nabil Aouf
2010 B conf
SMC
Yacine Morsly, Mohand Saïd Djouadi, Nabil Aouf
2010 conf
ITSC
Diego Rodriguez, Nabil Aouf
2009 conf
ICDP
Mohamed Sadek Kemouche, Nabil Aouf
2009 conf
ICONS
Yacine Morsly, Nabil Aouf, Mohand Saïd Djouadi
2009 J jnl
J. Intell. Robotic Syst.
Abdelkrim Nemra, Nabil Aouf
2009 J jnl
J. Intell. Robotic Syst.
Nabil Aouf, Aníbal Ollero, Jurek Z. Sasiadek
2009 J jnl
Int. J. Comput. Intell. Appl.
Ming-Wei Hong, Chun-Liang Lin, Bing-Min Shiu, Nabil Aouf
2008 C conf
FUSION
Mohamed Sadek Kemouche, Nabil Aouf
2008 A conf
BMVC
M. Kharbat, Nabil Aouf, Antonios Tsourdos, Brian A. White
2007 B conf
AVSS
M. Kharbat, Nabil Aouf, Antonios Tsourdos, Brian A. White
2004 conf
RAM
Nabil Aouf, Hani Rajabi, Nadim Rajabi, Harith Alanbari, Claude Perron
2002 C conf
ACC
Nabil Aouf, Benoit Boulet, Ruxandra M. Botez
2002 J jnl
IEEE Trans. Control. Syst. Technol.
Nabil Aouf, Benoit Boulet, Ruxandra M. Botez
2002 C conf
ACC
Nabil Aouf, Declan G. Bates
2001 C conf
ACC
Nabil Aouf, Benoit Boulet, Ruxandra M. Botez
2000 C conf
ACC
Nabil Aouf, Benoit Boulet, Ruxandra M. Botez
redb/extractors/decompiler/bninja/analysis/cfg_features.py
← Index redb/extractors/decompiler/bninja/analysis/cfg_features.py python
import struct
from collections import deque
from typing import Optional

import blake3
import mmh3


# ---------------------------------------------------------------------------
# Task 1.1: Core Graph Utilities
# ---------------------------------------------------------------------------

def bfs_order(successors: list[list[int]], n: int) -> list[int]:
    """
    BFS traversal from node 0 (entry block), returns node indices in visit order.
    Unreachable nodes appended at the end.
    """
    if n == 0:
        return []

    visited = set()
    order = []
    queue = deque([0])
    visited.add(0)

    while queue:
        idx = queue.popleft()
        order.append(idx)
        for target in successors[idx]:
            if target not in visited:
                visited.add(target)
                queue.append(target)

    # Append unreachable blocks (dead code)
    for i in range(n):
        if i not in visited:
            order.append(i)

    return order


def bfs_max_depth(successors: list[list[int]], n: int) -> int:
    """
    Maximum BFS depth from entry block (node 0).
    Replaces the per-block depth column with a single scalar.
    """
    if n == 0:
        return 0

    depth = {0: 0}
    max_d = 0
    queue = deque([0])

    while queue:
        node = queue.popleft()
        for s in successors[node]:
            if s not in depth:
                depth[s] = depth[node] + 1
                if depth[s] > max_d:
                    max_d = depth[s]
                queue.append(s)

    return max_d


# ---------------------------------------------------------------------------
# Task 1.2: Back-Edge Detection (Iterative DFS)
# ---------------------------------------------------------------------------

def count_back_edges(successors: list[list[int]], n: int) -> int:
    """
    Count natural loops via iterative DFS back-edge detection.
    A back edge is an edge to a GRAY (in-stack) node.

    Iterative to avoid stack overflow on functions with 1000+ blocks
    (common in obfuscated malware, VM dispatchers, unrolled loops).
    """
    if n == 0:
        return 0

    WHITE, GRAY, BLACK = 0, 1, 2
    color = [WHITE] * n
    back_edges = 0

    stack = [(0, iter(successors[0]))]
    color[0] = GRAY

    while stack:
        u, children = stack[-1]
        try:
            v = next(children)
            if color[v] == GRAY:
                back_edges += 1
            elif color[v] == WHITE:
                color[v] = GRAY
                stack.append((v, iter(successors[v])))
        except StopIteration:
            color[u] = BLACK
            stack.pop()

    return back_edges


# ---------------------------------------------------------------------------
# Task 1.3: Topology Hash
# ---------------------------------------------------------------------------

def compute_topology_hash(
    successors: list[list[int]],
    bfs: list[int],
    n: int,
) -> bytes:
    """
    BLAKE3 hash of BFS-ordered canonical adjacency.
    Pure graph shape — ignores all block content.
    Two functions with identical control flow structure produce identical hashes.

    Returns 16 bytes (128-bit).
    """
    if n == 0:
        return b'\x00' * 16

    # Remap: original index -> BFS position
    remap = {original: position for position, original in enumerate(bfs)}

    canonical = bytearray()
    for position in range(n):
        original_idx = bfs[position]
        remapped_succs = sorted(
            remap[s] for s in successors[original_idx] if s in remap
        )
        # Pack: node_index (2 bytes) + num_successors (1 byte) + successor indices (2 bytes each)
        canonical.extend(struct.pack('<HB', position, len(remapped_succs)))
        for s in remapped_succs:
            canonical.extend(struct.pack('<H', s))

    return blake3.blake3(bytes(canonical)).digest(length=16)


# ---------------------------------------------------------------------------
# Task 1.4: MD-Index (Top-Down and Bottom-Up)
# ---------------------------------------------------------------------------

def compute_md_index_topdown(
    successors: list[list[int]],
    predecessors: list[list[int]],
    bfs: list[int],
) -> int:
    """
    BinDiff-style top-down MD-index.
    Hash of (in_degree, out_degree) sequence in BFS order from entry.
    Returns UInt64.
    """
    if not bfs:
        return 0

    degree_bytes = bytearray()
    for idx in bfs:
        in_deg = min(len(predecessors[idx]), 255)
        out_deg = min(len(successors[idx]), 255)
        degree_bytes.extend(struct.pack('<BB', in_deg, out_deg))

    h = blake3.blake3(bytes(degree_bytes)).digest(length=8)
    return struct.unpack('<Q', h)[0]


def compute_md_index_bottomup(
    successors: list[list[int]],
    predecessors: list[list[int]],
    n: int,
) -> int:
    """
    Bottom-up MD-index: BFS from exit blocks (no successors),
    traversing edges in reverse.
    Returns UInt64.
    """
    if n == 0:
        return 0

    exits = [i for i in range(n) if len(successors[i]) == 0]
    if not exits:
        exits = [n - 1]  # Fallback: use last block

    visited = set(exits)
    order = []
    queue = deque(exits)

    while queue:
        idx = queue.popleft()
        order.append(idx)
        for pred in predecessors[idx]:
            if pred not in visited:
                visited.add(pred)
                queue.append(pred)

    # Append unreachable blocks
    for i in range(n):
        if i not in visited:
            order.append(i)

    degree_bytes = bytearray()
    for idx in order:
        in_deg = min(len(predecessors[idx]), 255)
        out_deg = min(len(successors[idx]), 255)
        degree_bytes.extend(struct.pack('<BB', in_deg, out_deg))

    h = blake3.blake3(bytes(degree_bytes)).digest(length=8)
    return struct.unpack('<Q', h)[0]


# ---------------------------------------------------------------------------
# Task 1.5: Prime Product
# ---------------------------------------------------------------------------

# Small primes assigned to LLIL opcode categories.
# Keys are the integer values of binaryninja.LowLevelILOperation enum members.
# We use integer keys so this module doesn't import binaryninja.
#
# Mapping rationale: same operation class -> same prime.
# Using LLIL (not native asm) makes this architecture-independent.
#
# Populated at import time by cfg.py using the real LowLevelILOperation enum values.
# Unknown ops map to prime 1 (identity element) in compute_prime_product().
LLIL_OP_PRIMES: dict[int, int] = {}


def compute_prime_product(llil_operations: list[int]) -> int:
    """
    Product of small primes assigned to each LLIL opcode.
    Position-independent: block reordering doesn't change the result.
    Mod 2^64 for fixed-size storage.

    Args:
        llil_operations: flat list of LLIL operation enum integer values
                         for all instructions in the function.
    Returns:
        UInt64 prime product, or 0 if no instructions.
    """
    if not llil_operations:
        return 0

    product = 1
    for op in llil_operations:
        prime = LLIL_OP_PRIMES.get(op, 1)
        product = (product * prime) % (2**64)

    return product


# ---------------------------------------------------------------------------
# Task 1.6: ACFG Block Features
# ---------------------------------------------------------------------------

# Instruction category indices for ACFG feature vectors
CAT_ARITHMETIC = 0
CAT_LOGIC = 1
CAT_TRANSFER = 2
CAT_CALL = 3
CAT_COMPARISON = 4
CAT_MEMORY = 5
CAT_OTHER = 6

# Maps LLIL operation integer values to category indices.
# Populated at import time by cfg.py using the real LowLevelILOperation enum.
LLIL_OP_CATEGORIES: dict[int, int] = {}


def build_block_features(
    block_llil_ops: list[list[int]],
    successors: list[list[int]],
    n: int,
) -> list[list[int]]:
    """
    Extract Gemini-style ACFG features per block.

    Args:
        block_llil_ops: per-block list of LLIL operation integer values.
                        block_llil_ops[i] is the list of ops for block i.
                        Empty list if LLIL unavailable for that block.
        successors: index-based adjacency list.
        n: number of blocks.

    Returns:
        List of [instr_count, arithmetic, logic, transfer, call, comparison,
                 memory, successor_count] per block. All values capped at 65535.
    """
    features = []
    for i in range(n):
        cats = [0, 0, 0, 0, 0, 0, 0]
        ops = block_llil_ops[i] if i < len(block_llil_ops) else []
        for op in ops:
            cat = LLIL_OP_CATEGORIES.get(op, CAT_OTHER)
            cats[cat] += 1

        instr_count = len(ops)
        features.append([
            min(instr_count, 65535),
            min(cats[CAT_ARITHMETIC], 65535),
            min(cats[CAT_LOGIC], 65535),
            min(cats[CAT_TRANSFER], 65535),
            min(cats[CAT_CALL], 65535),
            min(cats[CAT_COMPARISON], 65535),
            min(cats[CAT_MEMORY], 65535),
            min(len(successors[i]), 65535),
        ])

    return features


# ---------------------------------------------------------------------------
# Task 1.7: CFG Feature TLSH
# ---------------------------------------------------------------------------

def compute_cfg_feature_tlsh(
    bb_features: list[list[int]],
    bfs: list[int],
) -> Optional[str]:
    """
    TLSH hash of BFS-ordered per-block feature vectors.
    Captures both structure (BFS ordering) and instruction distribution.

    Returns TLSH hex string or None if too few bytes for TLSH (< 50).
    """
    import tlsh as _tlsh

    feature_bytes = bytearray()
    for idx in bfs:
        feats = bb_features[idx]
        feature_bytes.extend(struct.pack(
            '<HBBBBBBB',
            min(feats[0], 65535),
            min(feats[1], 255),
            min(feats[2], 255),
            min(feats[3], 255),
            min(feats[4], 255),
            min(feats[5], 255),
            min(feats[6], 255),
            min(feats[7], 255),
        ))

    if len(feature_bytes) < 50:
        return None

    try:
        h = _tlsh.hash(bytes(feature_bytes))
        return h if h and h != 'TNULL' else None
    except Exception:
        return None


# ---------------------------------------------------------------------------
# Task 1.8: WL-MinHash
# ---------------------------------------------------------------------------

# Pre-computed seeds for MinHash permutations.
NUM_WL_MINHASH_PERMS = 128
_WL_MINHASH_SEEDS = list(range(NUM_WL_MINHASH_PERMS))  # Seeds 0..127


def compute_wl_minhash(
    successors: list[list[int]],
    predecessors: list[list[int]],
    bb_features: list[list[int]],
    n: int,
    iterations: int = 3,
) -> list[int]:
    """
    Weisfeiler-Leman MinHash for fuzzy topology similarity.

    Initial labels: mmh3 hash of per-block ACFG feature tuple (content-aware).
    WL refinement: incorporate sorted neighbor labels at each iteration.
    MinHash: 128-permutation signature over shingle set.

    Returns list of 128 uint8 values, or [255]*128 sentinel for empty functions.
    """
    if n == 0:
        return [255] * NUM_WL_MINHASH_PERMS

    # Initial labels: hash of instruction category tuple per block
    labels = []
    for i in range(n):
        feats = bb_features[i] if i < len(bb_features) else [0] * 8
        # mmh3 with seed=0 for initial labels
        label = mmh3.hash(str(tuple(feats)), 0) & 0xFFFFFFFF
        labels.append(label)

    # Collect shingles: (iteration, label) pairs as strings for mmh3
    shingles: set[str] = set()

    # Iteration 0: individual block labels
    for label in labels:
        shingles.add(f"0:{label}")

    # WL iterations: refine labels by neighborhood aggregation
    for iteration in range(1, iterations + 1):
        new_labels = []
        for i in range(n):
            succ_labels = tuple(sorted(labels[s] for s in successors[i]))
            pred_labels = tuple(sorted(labels[p] for p in predecessors[i]))
            composite = f"{labels[i]}|{succ_labels}|{pred_labels}"
            new_label = mmh3.hash(composite, 0) & 0xFFFFFFFF
            new_labels.append(new_label)
            shingles.add(f"{iteration}:{new_label}")
        labels = new_labels

    if not shingles:
        return [255] * NUM_WL_MINHASH_PERMS

    # Compute MinHash signature using mmh3 with different seeds
    shingle_list = list(shingles)
    signature = []
    for seed in _WL_MINHASH_SEEDS:
        min_val = 0xFFFFFFFF
        for s in shingle_list:
            h = mmh3.hash(s, seed) & 0xFFFFFFFF
            if h < min_val:
                min_val = h
        # Compress to uint8 for storage
        signature.append(min_val & 0xFF)

    return signature


# ---------------------------------------------------------------------------
# Task 1.9: Packed Adjacency
# ---------------------------------------------------------------------------

def pack_adjacency(successors: list[list[int]]) -> list[int]:
    """
    Pack CFG edges as Array(UInt32).
    Each UInt32 = (source_index << 16) | target_index.
    Supports up to 65,535 blocks per function.
    """
    edges = []
    for src, targets in enumerate(successors):
        for tgt in targets:
            if src < 65536 and tgt < 65536:
                edges.append((src << 16) | tgt)
    return edges