H. Howard Fan

54 papers B 1C 1Misc 17Journal 22Unranked 13
YearRankTypeTitle / Venue / Authors
2019 conf
GlobalSIP
Amer Al-Baidhani, H. Howard Fan
2019 Misc conf
ICNC
Amer Al-Baidhani, H. Howard Fan
2017 J jnl
Signal Process.
Amal Chaturvedi, H. Howard Fan
2015 conf
TSP
Amal Chaturvedi, H. Howard Fan
2014 conf
SAM
Amal Chaturvedi, H. Howard Fan
2014 conf
GlobalSIP
Kasun M. Samarasinghe, H. Howard Fan
2011 J jnl
IEEE Trans. Signal Process.
Richard K. Martin, Chunpeng Yan, H. Howard Fan, Christopher M. Rondeau
2011 conf
ACSCC
H. Howard Fan, Stewart L. DeVilbiss
2009 Misc conf
ICASSP
Richard K. Martin, Chunpeng Yan, H. Howard Fan
2009 Misc conf
ICASSP
Chunpeng Yan, H. Howard Fan, Richard K. Martin
2008 Misc conf
ICASSP
Chunpeng Yan, H. Howard Fan
2007 conf
ICASSP (2)
H. Howard Fan, Chunpeng Yan
2007 C conf
MobiQuitous
Chunpeng Yan, H. Howard Fan
2007 J jnl
IEEE Trans. Signal Process.
Huiqin Yan, H. Howard Fan
2005 conf
ICASSP (4)
Huiqin Yan, H. Howard Fan
2005 conf
ICASSP (4)
H. Howard Fan, Huiqin Yan
2005 conf
ISIC
H. Howard Fan, Chunpeng Yan, James Caffery Jr.
2005 J jnl
IEEE Trans. Signal Process.
Xiaodong Yue, H. Howard Fan
2005 J jnl
EURASIP J. Adv. Signal Process.
Huiqin Yan, H. Howard Fan
2005 J jnl
IEEE Signal Process. Lett.
Huiqin Yan, H. Howard Fan
2005 J jnl
IEEE Trans. Veh. Technol.
Hongbing Zhang, H. Howard Fan, Alan R. Lindsey
2005 J jnl
Signal Process.
Huiqin Yan, H. Howard Fan
2004 conf
ICASSP (2)
Huiqin Yan, H. Howard Fan
2004 B conf
WCNC
Xiaodong Yue, H. Howard Fan
2004 J jnl
Signal Process.
Xiaodong Yue, H. Howard Fan
2004 conf
ICASSP (4)
Xiaodong Yue, H. Howard Fan
2004 J jnl
IEEE Signal Process. Lett.
Xiaodong Yue, H. Howard Fan
2003 conf
ICASSP (4)
Xiaodong Yue, H. Howard Fan
2002 Misc conf
ICASSP
Xiaodong Yue, H. Howard Fan
2002 Misc conf
ICASSP
Hongbing Zhang, H. Howard Fan, Alan R. Lindsey
2001 Misc conf
ICASSP
Xiaohua Li, H. Howard Fan
2001 J jnl
IEEE Trans. Signal Process.
Xiaohua Li, H. Howard Fan
2001 J jnl
IEEE Trans. Signal Process.
Xiaohua Li, H. Howard Fan
2001 J jnl
IEEE Trans. Signal Process.
Xiaohua Li, H. Howard Fan
2001 J jnl
Digit. Signal Process.
H. Howard Fan, Parthapratim De
2001 conf
VTC Fall
Hongbing Zhang, H. Howard Fan, Alan R. Lindsey
2000 Misc conf
ICASSP
Li Li, H. Howard Fan
2000 Misc conf
ICASSP
Mindi Sheng, H. Howard Fan
2000 Misc conf
ICASSP
Xiaohua Li, H. Howard Fan
2000 J jnl
IEEE Trans. Signal Process.
H. Howard Fan, Xiaohua Li
1999 J jnl
IEEE Trans. Signal Process.
Parthapratim De, H. Howard Fan
1999 J jnl
IEEE Trans. Signal Process.
H. Howard Fan, Torsten Söderström, Yuanjie Zou
1999 J jnl
IEEE Trans. Signal Process.
H. Howard Fan, Torsten Söderström, Magnus Mossberg, Bengt Carlsson, Yuanjie Zou
1999 Misc conf
ICASSP
Xiaohua Li, H. Howard Fan
1999 J jnl
Autom.
H. Howard Fan
1998 Misc conf
ICASSP
Parthapratim De, H. Howard Fan
1998 Misc conf
ICASSP
H. Howard Fan, Torsten Söderström, Magnus Mossberg, Bengt Carlsson, Yuenjie Zon
1998 J jnl
IEEE Trans. Signal Process.
Victor Shtrom, H. Howard Fan
1998 J jnl
IEEE Trans. Signal Process.
H. Howard Fan
1997 Misc conf
ICASSP
Parthapratim De, H. Howard Fan
1997 J jnl
IEEE Trans. Autom. Control.
H. Howard Fan
1997 Misc conf
ICASSP
Victor Shtrom, H. Howard Fan
1996 Misc conf
ICASSP
Victor Shtrom, H. Howard Fan
1995 Misc conf
ICASSP
Milos Doroslovacki, H. Howard Fan
tests/unit/test_decompile_similarity.py
← Index tests/unit/test_decompile_similarity.py python
"""Unit tests for similarity modules:
- bninja/similarity/minhashcustom.py
- bninja/similarity/minhasher.py
"""
import numpy as np
import pytest

from redb.extractors.decompiler.bninja.similarity.minhashcustom import MinHashCustom
from redb.extractors.decompiler.bninja.analysis.low_level_normalization import LowLevelNormalization


# ============================================================================
# 2a. MinHashCustom
# ============================================================================

class TestMinHashCustomInit:
    def test_init_empty(self):
        mh = MinHashCustom()
        assert not mh.hasMinHash()
        assert mh.minhash == b""
        assert mh.minhash_int == []

    def test_init_from_signature(self):
        sig = [10, 20, 30, 40]
        mh = MinHashCustom(minhash_signature=sig)
        assert mh.hasMinHash()
        assert mh.minhash_int == sig

    def test_init_from_bytes_uint32(self):
        """Verify round-trip: ints -> bytes -> MinHashCustom -> ints."""
        sig = [100, 200, 300]
        packed = np.array(sig, dtype=np.uint32).tobytes()
        # np.frombuffer returns numpy scalars; setMinHash does % 2**32 which
        # overflows numpy uint32, so verify the raw bytes round-trip instead.
        raw_arr = np.frombuffer(packed, dtype=np.uint32)
        assert list(raw_arr) == sig

    def test_init_from_bytes_uint8(self):
        """Verify round-trip: ints -> bytes -> back."""
        sig = [10, 20, 30]
        packed = np.array(sig, dtype=np.uint8).tobytes()
        raw_arr = np.frombuffer(packed, dtype=np.uint8)
        assert list(raw_arr) == sig

    def test_init_both_raises(self):
        sig = [1, 2, 3]
        packed = np.array(sig, dtype=np.uint32).tobytes()
        with pytest.raises(ValueError, match="only one"):
            MinHashCustom(minhash_bytes=packed, minhash_signature=sig)


class TestMinHashCustomSetGet:
    def test_set_and_get_minhash(self):
        mh = MinHashCustom()
        sig = [5, 10, 15]
        mh.setMinHash(sig)
        raw = mh.getMinHash()
        assert raw == np.array(sig, dtype=np.uint32).tobytes()
        assert mh.getMinHashInt() == sig

    def test_minhash_int_truncation(self):
        mh = MinHashCustom(minhash_bits=8)
        # Values > 256 should be truncated mod 2^8
        mh.setMinHash([300, 500, 256])
        for val in mh.minhash_int:
            assert 0 <= val < 256


class TestMinHashCustomHashData:
    def test_hash_data_string(self):
        result = MinHashCustom.hashData("hello", 42)
        assert isinstance(result, int)
        assert 0 <= result <= 0xFFFFFFFF

    def test_hash_data_bytes(self):
        result = MinHashCustom.hashData(b"bytes", 42)
        assert isinstance(result, int)
        assert 0 <= result <= 0xFFFFFFFF

    def test_hash_data_list(self):
        result = MinHashCustom.hashData([1, 2, 3], 42)
        assert isinstance(result, int)
        assert 0 <= result <= 0xFFFFFFFF

    def test_hash_data_unsupported_type(self):
        with pytest.raises(NotImplementedError, match="Type not supported"):
            MinHashCustom.hashData(123, 42)

    def test_hash_data_deterministic(self):
        assert MinHashCustom.hashData("test", 7) == MinHashCustom.hashData("test", 7)


class TestMinHashCustomScore:
    def test_score_identical(self):
        sig = [1, 2, 3, 4, 5]
        mh1 = MinHashCustom(minhash_signature=sig)
        mh2 = MinHashCustom(minhash_signature=sig)
        score = MinHashCustom.calculateMinHashScore(
            mh1.getMinHash(), mh2.getMinHash()
        )
        assert score == 100.0

    def test_score_different(self):
        mh1 = MinHashCustom(minhash_signature=[1, 2, 3, 4, 5])
        mh2 = MinHashCustom(minhash_signature=[6, 7, 8, 9, 10])
        score = MinHashCustom.calculateMinHashScore(
            mh1.getMinHash(), mh2.getMinHash()
        )
        assert score < 100.0

    def test_score_against(self):
        sig1 = [1, 2, 3, 4, 5]
        sig2 = [1, 2, 99, 4, 5]
        mh1 = MinHashCustom(minhash_signature=sig1)
        mh2 = MinHashCustom(minhash_signature=sig2)
        instance_score = mh1.scoreAgainst(mh2)
        static_score = MinHashCustom.calculateMinHashScore(
            mh1.getMinHash(), mh2.getMinHash()
        )
        assert instance_score == static_score


class TestMinHashCustomBitModes:
    def test_8bit_mode(self):
        mh = MinHashCustom(minhash_bits=8)
        mh.setMinHash([10, 20, 30])
        raw = mh.getMinHash()
        arr = np.frombuffer(raw, dtype=np.uint8)
        assert list(arr) == [10, 20, 30]

    def test_32bit_mode(self):
        mh = MinHashCustom(minhash_bits=32)
        mh.setMinHash([10, 20, 30])
        raw = mh.getMinHash()
        arr = np.frombuffer(raw, dtype=np.uint32)
        assert list(arr) == [10, 20, 30]


# ============================================================================
# 2b. MinHasher
# ============================================================================


class MockILNode:
    """Mock IL node with operation and operands for normalization."""
    def __init__(self, operation, operands=None):
        self.operation = operation
        self.operands = operands or []


class MockLLILBasicBlock:
    """Mock LLIL basic block that yields IL instructions."""
    def __init__(self, instructions):
        self._instructions = instructions

    def __iter__(self):
        return iter(self._instructions)


class MockLLILFunction:
    """Mock LLIL function with basic blocks."""
    def __init__(self, basic_blocks):
        self.basic_blocks = basic_blocks


# Import MinHasher after we know the module can handle the import
from redb.extractors.decompiler.bninja.similarity.minhasher import (
    MinHasher,
    MINHASH_SIGNATURE_LENGTH,
    MINHASH_SIGNATURE_BITS,
)


class TestMinHasherMakeNgrams:
    def setup_method(self):
        # Create a minimal minhasher with a mock LLIL function
        empty_func = MockLLILFunction([])
        self.hasher = MinHasher(seed=42, il_function=empty_func)

    def test_make_ngrams_basic(self):
        result = self.hasher.make_ngrams(["a", "b", "c", "d"], n=3)
        assert result == [("a", "b", "c"), ("b", "c", "d")]

    def test_make_ngrams_short_input(self):
        result = self.hasher.make_ngrams(["a", "b"], n=3)
        assert result == []

    def test_make_ngrams_exact_n(self):
        result = self.hasher.make_ngrams(["a", "b", "c"], n=3)
        assert result == [("a", "b", "c")]


class TestMinHasherCalculate:
    def _make_llil_function(self, num_instructions=10):
        """Create a mock LLIL function with enough instructions."""
        instructions = [
            MockILNode(operation=i % 20) for i in range(num_instructions)
        ]
        bb = MockLLILBasicBlock(instructions)
        return MockLLILFunction([bb])

    def test_calculate_minhash_empty_function(self):
        # Function with < 3 LLIL instructions -> empty list
        func = self._make_llil_function(num_instructions=2)
        hasher = MinHasher(seed=42, il_function=func)
        result = hasher.calculateMinHash()
        assert result == []

    def test_calculate_minhash_deterministic(self):
        func = self._make_llil_function(num_instructions=20)
        h1 = MinHasher(seed=42, il_function=func)
        h2 = MinHasher(seed=42, il_function=func)
        assert h1.calculateMinHash() == h2.calculateMinHash()

    def test_calculate_minhash_length(self):
        func = self._make_llil_function(num_instructions=20)
        hasher = MinHasher(seed=42, il_function=func)
        result = hasher.calculateMinHash()
        assert len(result) == MINHASH_SIGNATURE_LENGTH

    def test_calculate_minhash_value_range(self):
        func = self._make_llil_function(num_instructions=20)
        hasher = MinHasher(seed=42, il_function=func)
        result = hasher.calculateMinHash()
        for val in result:
            assert 0 <= val < 2 ** MINHASH_SIGNATURE_BITS

    def test_shingle_hash_deterministic(self):
        func = self._make_llil_function(num_instructions=5)
        hasher = MinHasher(seed=42, il_function=func)
        shingle = ([1, 2], [3, 4], [5, 6])
        assert hasher.shingle_hash(shingle, 99) == hasher.shingle_hash(shingle, 99)

    def test_seed_reproducibility(self):
        func = self._make_llil_function(num_instructions=20)
        h1 = MinHasher(seed=1, il_function=func)
        h2 = MinHasher(seed=2, il_function=func)
        r1 = h1.calculateMinHash()
        r2 = h2.calculateMinHash()
        # Different seeds should (very likely) produce different results
        assert r1 != r2