Weird Number

p
"""
https://en.wikipedia.org/wiki/Weird_number

Fun fact: The set of weird numbers has positive asymptotic density.
"""

from math import sqrt


def factors(number: int) -> list[int]:
    """
    >>> factors(12)
    [1, 2, 3, 4, 6]
    >>> factors(1)
    [1]
    >>> factors(100)
    [1, 2, 4, 5, 10, 20, 25, 50]

    # >>> factors(-12)
    # [1, 2, 3, 4, 6]
    """

    values = [1]
    for i in range(2, int(sqrt(number)) + 1, 1):
        if number % i == 0:
            values.append(i)
            if int(number // i) != i:
                values.append(int(number // i))
    return sorted(values)


def abundant(n: int) -> bool:
    """
    >>> abundant(0)
    True
    >>> abundant(1)
    False
    >>> abundant(12)
    True
    >>> abundant(13)
    False
    >>> abundant(20)
    True

    # >>> abundant(-12)
    # True
    """
    return sum(factors(n)) > n


def semi_perfect(number: int) -> bool:
    """
    >>> semi_perfect(0)
    True
    >>> semi_perfect(1)
    True
    >>> semi_perfect(12)
    True
    >>> semi_perfect(13)
    False

    # >>> semi_perfect(-12)
    # True
    """
    values = factors(number)
    r = len(values)
    subset = [[0 for i in range(number + 1)] for j in range(r + 1)]
    for i in range(r + 1):
        subset[i][0] = True

    for i in range(1, number + 1):
        subset[0][i] = False

    for i in range(1, r + 1):
        for j in range(1, number + 1):
            if j < values[i - 1]:
                subset[i][j] = subset[i - 1][j]
            else:
                subset[i][j] = subset[i - 1][j] or subset[i - 1][j - values[i - 1]]

    return subset[r][number] != 0


def weird(number: int) -> bool:
    """
    >>> weird(0)
    False
    >>> weird(70)
    True
    >>> weird(77)
    False
    """
    return abundant(number) and not semi_perfect(number)


if __name__ == "__main__":
    import doctest

    doctest.testmod(verbose=True)
    for number in (69, 70, 71):
        print(f"{number} is {'' if weird(number) else 'not '}weird.")