Buggy python submission (verdict: Time Limit Exceeded):
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
sys.setrecursionlimit(10**7)
from pprint import pprint as pp
from pprint import pformat as pf
# @pysnooper.snoop()
#import pysnooper # debug

import math
#from sortedcontainers import SortedList, SortedDict, SortedSet # no in atcoder
import bisect
from fractions import Fraction
from collections import defaultdict


def mode(a, b):
    # retrun dict_key, arr_key
    if a == 0 and b == 0:
        return 0, 0
    if a == 0:
        return 'ab', 0
    if b == 0:
        return 'ab', 1
    x = Fraction(a, b)
    y = Fraction(-1 * b, a)
    if x > y:
        return x, 0
    else:
        return y, 1

MOD = 1000000007

if __name__ == '__main__':

    n = int(input())

    d = defaultdict(lambda: [0, 0])
    zero = 0
    for _ in range(n):
        a, b = list(map(int, input().split()))
        dkey, akey = mode(a, b)
        if dkey == 0:
            zero += 1
        else:
            d[dkey][akey] += 1
    #print('d') # debug
    #pp(d) # debug

    ans = 1
    for pair in d.values():
        tmp = pow(2, pair[0], MOD) - 1 + pow(2, pair[1], MOD) - 1 + 1
        ans *= tmp
    ans += zero - 1
    ans %= MOD
    #print('ans') # debug
    print(ans)

    #print('\33[32m' + 'end' + '\033[0m') # debug


Fixed submission:
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
sys.setrecursionlimit(10**7)
from pprint import pprint as pp
from pprint import pformat as pf
# @pysnooper.snoop()
#import pysnooper # debug

import math
#from sortedcontainers import SortedList, SortedDict, SortedSet # no in atcoder
import bisect
from fractions import Fraction
from collections import defaultdict

def is_same_sign(a, b):
    if a > 0 and b > 0:
        return True
    if a < 0 and b < 0:
        return True
    return False

def fraction_taple(a, b):
    g = math.gcd(a, b)
    if is_same_sign(a, b):
        s = 1
    else:
        s = -1
    a = abs(a) // g
    b = abs(b) // g
    return (s, a, b)

def mode(a, b):
    # retrun dict_key, arr_key
    if a == 0 and b == 0:
        return 0, 0
    if a == 0:
        return 'ab', 0
    if b == 0:
        return 'ab', 1
    x = fraction_taple(a, b)
    y = fraction_taple(-1 * b, a)
    if x > y:
        return x, 0
    else:
        return y, 1

MOD = 1000000007

if __name__ == '__main__':

    n = int(input())

    d = defaultdict(lambda: [0, 0])
    zero = 0
    for _ in range(n):
        a, b = list(map(int, input().split()))
        dkey, akey = mode(a, b)
        if dkey == 0:
            zero += 1
        else:
            d[dkey][akey] += 1
    #print('d') # debug
    #pp(d) # debug

    ans = 1
    for pair in d.values():
        tmp = pow(2, pair[0], MOD) - 1 + pow(2, pair[1], MOD) - 1 + 1
        ans *= tmp
    ans += zero - 1
    ans %= MOD
    #print('ans') # debug
    print(ans)

    #print('\33[32m' + 'end' + '\033[0m') # debug

Buggy python submission (verdict: Time Limit Exceeded):
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
sys.setrecursionlimit(10**7)
from pprint import pprint as pp
from pprint import pformat as pf
# @pysnooper.snoop()
#import pysnooper # debug

import math
#from sortedcontainers import SortedList, SortedDict, SortedSet # no in atcoder
import bisect
from fractions import Fraction
from collections import defaultdict

MOD = 1000000007

class Sardine:
    def __init__(self, a, b):
        if a == 0 and b == 0:
            self.type_ = 0
        elif a == 0:
            self.type_ = 'a'
        elif b == 0:
            self.type_ = 'b'
        else:
            self.type_ = Fraction(a, b)

def combi(x, y):
    res = pow(2, x, MOD) - 1 + pow(2, y, MOD) - 1 + 1
    #print('res', x, y) # debug
    #print(res) # debug
    return res

def calc_cross_type(frac):
    cross = Fraction(-1 * frac.denominator, frac.numerator)
    #print('cross', frac, cross) # debug
    return cross

def count_up(types):
    ans = 0
    seed = 1
    seed *= combi(types['a'], types['b'])
    keys = list(types.keys())
    for type_ in keys:
        if not (type(type_) == Fraction and type_ > 0):
            continue
        count = types[type_]
        cross_type = calc_cross_type(type_)
        cross_count = types[cross_type]
        seed = (seed * combi(count, cross_count)) % MOD
    ans += seed
    ans += types[0]
    return ans - 1 # remove no sellect

if __name__ == '__main__':
    n = int(input())
    types = defaultdict(lambda: 0)
    for _ in range(n):
        a, b = list(map(int, input().split()))
        sardine = Sardine(a, b)
        types[sardine.type_] += 1
        if type(sardine.type_) is Fraction:
            cross_type = calc_cross_type(sardine.type_)
            types[cross_type]
    #print('types') # debug
    #pp(types) # debug
    ans = count_up(types)
    #print('ans') # debug
    print(ans)




    #print('\33[32m' + 'end' + '\033[0m') # debug


Fixed submission:
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
sys.setrecursionlimit(10**7)
from pprint import pprint as pp
from pprint import pformat as pf
# @pysnooper.snoop()
#import pysnooper # debug

import math
#from sortedcontainers import SortedList, SortedDict, SortedSet # no in atcoder
import bisect
from fractions import Fraction
from collections import defaultdict

def is_same_sign(a, b):
    if a > 0 and b > 0:
        return True
    if a < 0 and b < 0:
        return True
    return False

def fraction_taple(a, b):
    g = math.gcd(a, b)
    if is_same_sign(a, b):
        s = 1
    else:
        s = -1
    a = abs(a) // g
    b = abs(b) // g
    return (s, a, b)

def mode(a, b):
    # retrun dict_key, arr_key
    if a == 0 and b == 0:
        return 0, 0
    if a == 0:
        return 'ab', 0
    if b == 0:
        return 'ab', 1
    x = fraction_taple(a, b)
    y = fraction_taple(-1 * b, a)
    if x > y:
        return x, 0
    else:
        return y, 1

MOD = 1000000007

if __name__ == '__main__':

    n = int(input())

    d = defaultdict(lambda: [0, 0])
    zero = 0
    for _ in range(n):
        a, b = list(map(int, input().split()))
        dkey, akey = mode(a, b)
        if dkey == 0:
            zero += 1
        else:
            d[dkey][akey] += 1
    #print('d') # debug
    #pp(d) # debug

    ans = 1
    for pair in d.values():
        tmp = pow(2, pair[0], MOD) - 1 + pow(2, pair[1], MOD) - 1 + 1
        ans *= tmp
    ans += zero - 1
    ans %= MOD
    #print('ans') # debug
    print(ans)

    #print('\33[32m' + 'end' + '\033[0m') # debug

Buggy python submission (verdict: Runtime Error):
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
sys.setrecursionlimit(10**7)
from pprint import pprint as pp
from pprint import pformat as pf
# @pysnooper.snoop()
#import pysnooper # debug

import math
#from sortedcontainers import SortedList, SortedDict, SortedSet # no in atcoder
import bisect
from fractions import Fraction
from collections import defaultdict

MOD = 1000000007

def factorial(n, mod=None, memo=False):
    if memo:
        factorial.memo = [1] * (n + 1)
        for i in range(1, n + 1):
            if mod is None:
                factorial.memo[i] = i * factorial.memo[i - 1]
            else:
                factorial.memo[i] = i * factorial.memo[i - 1] % mod
    return factorial.memo[n]

def choose(n, r, mod=None):
    a = factorial(n)
    b = factorial(r)
    c = factorial(n - r)
    if mod is None:
        res = a // b // c
    else:
        # fermat's little theorem
        res = a * pow(b, mod - 2, mod) * pow(c, mod - 2, mod) % mod
    return res

class Sardine:
    def __init__(self, a, b):
        if a == 0 and b == 0:
            self.type_ = 0
        elif a == 0:
            self.type_ = 'a'
        elif b == 0:
            self.type_ = 'b'
        else:
            self.type_ = Fraction(a, b)

def sigma_choose(v):
    ans = 0
    i = 1
    while i <= v:
        ans += choose(v, i, MOD)
        ans %= MOD
        # for next
        i += 1
    return ans

def combi(x, y):
    res = sigma_choose(x) + sigma_choose(y) + 1
    #print('res') # debug
    #print(res) # debug
    return res

def calc_cross_type(frac):
    cross = Fraction(-1 * frac.denominator, frac.numerator)
    #print('cross', frac, cross) # debug
    return cross

def count_up(types):
    ans = 0
    seed = 1
    seed *= combi(types['a'], types['b'])
    keys = list(types.keys())
    for type_ in keys:
        if not (type(type_) == Fraction and type_ > 0):
            continue
        count = types[type_]
        cross_type = calc_cross_type(type_)
        cross_count = types[cross_type]
        seed = (seed * combi(count, cross_count)) % MOD
    ans += seed
    ans += types[0]
    return ans - 1 # remove no sellect

if __name__ == '__main__':
    factorial(2 * 10 ** 5, MOD, True)
    n = int(input())
    types = defaultdict(lambda: 0)
    for _ in range(n):
        a, b = list(map(int, input().split()))
        sardine = Sardine(a, b)
        types[sardine.type_] += 1
        cross_type = calc_cross_type(sardine.type_)
        types[cross_type]
    #print('types') # debug
    #pp(types) # debug
    ans = count_up(types)
    #print('ans') # debug
    print(ans)




    #print('\33[32m' + 'end' + '\033[0m') # debug


Fixed submission:
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
sys.setrecursionlimit(10**7)
from pprint import pprint as pp
from pprint import pformat as pf
# @pysnooper.snoop()
#import pysnooper # debug

import math
#from sortedcontainers import SortedList, SortedDict, SortedSet # no in atcoder
import bisect
from fractions import Fraction
from collections import defaultdict

def is_same_sign(a, b):
    if a > 0 and b > 0:
        return True
    if a < 0 and b < 0:
        return True
    return False

def fraction_taple(a, b):
    g = math.gcd(a, b)
    if is_same_sign(a, b):
        s = 1
    else:
        s = -1
    a = abs(a) // g
    b = abs(b) // g
    return (s, a, b)

def mode(a, b):
    # retrun dict_key, arr_key
    if a == 0 and b == 0:
        return 0, 0
    if a == 0:
        return 'ab', 0
    if b == 0:
        return 'ab', 1
    x = fraction_taple(a, b)
    y = fraction_taple(-1 * b, a)
    if x > y:
        return x, 0
    else:
        return y, 1

MOD = 1000000007

if __name__ == '__main__':

    n = int(input())

    d = defaultdict(lambda: [0, 0])
    zero = 0
    for _ in range(n):
        a, b = list(map(int, input().split()))
        dkey, akey = mode(a, b)
        if dkey == 0:
            zero += 1
        else:
            d[dkey][akey] += 1
    #print('d') # debug
    #pp(d) # debug

    ans = 1
    for pair in d.values():
        tmp = pow(2, pair[0], MOD) - 1 + pow(2, pair[1], MOD) - 1 + 1
        ans *= tmp
    ans += zero - 1
    ans %= MOD
    #print('ans') # debug
    print(ans)

    #print('\33[32m' + 'end' + '\033[0m') # debug

Buggy python submission (verdict: Runtime Error):
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
sys.setrecursionlimit(10**7)
from pprint import pprint as pp
from pprint import pformat as pf
# @pysnooper.snoop()
#import pysnooper # debug

import math
#from sortedcontainers import SortedList, SortedDict, SortedSet # no in atcoder
import bisect
from fractions import Fraction

# NG: ai / bi (atk) = - bj / aj (agi)

mod = 1000000007

class Solver:

    def __init__(self, n):
        self.n = n
        self.atk = []
        self.agi = {}
        self.ans = 0

    def fishing(self, id_, a, b):
        atk = Fraction(a, b)
        self.atk.append(atk)
        agi = Fraction(-1 * b / a)
        if agi not in self.agi:
            self.agi[agi] = []
        self.agi[agi].append(id_)

    def check(self, i):
        atk = self.atk[i]
        if atk in self.agi:
            #print(self.agi[atk]) # debug
            return self.agi[atk]
        else:
            return []

    def run(self):
        ng = [False] * self.n
        free = 0
        self.f(0, ng[:], free)
        return self.ans - 1

    def f(self, i, ng, free):
        #print('f') # debug
        #print('ng') # debug
        #print(ng) # debug
        while i < self.n:
            #print('i') # debug
            #print(i) # debug
            if ng[i]:
                i += 1
                continue
            enemy = self.check(i)
            #print('enemy') # debug
            #print(enemy) # debug
            if len(enemy) == 0:
                free += 1
            else:
                #print('else') # debug
                self.f(i + 1, ng[:], free)
                for e in enemy:
                    ng[e] = True
            i += 1
        self.ans += 2 ** free % mod
        #print('f end', free) # debug





if __name__ == '__main__':
    n = int(input())
    solver = Solver(n)
    for i in range(n):
        a, b = list(map(int, input().split()))
        solver.fishing(i, a, b)

    ans = solver.run()
    #print('ans') # debug
    print(ans)


    #print('\33[32m' + 'end' + '\033[0m') # debug


Fixed submission:
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
sys.setrecursionlimit(10**7)
from pprint import pprint as pp
from pprint import pformat as pf
# @pysnooper.snoop()
#import pysnooper # debug

import math
#from sortedcontainers import SortedList, SortedDict, SortedSet # no in atcoder
import bisect
from fractions import Fraction
from collections import defaultdict

def is_same_sign(a, b):
    if a > 0 and b > 0:
        return True
    if a < 0 and b < 0:
        return True
    return False

def fraction_taple(a, b):
    g = math.gcd(a, b)
    if is_same_sign(a, b):
        s = 1
    else:
        s = -1
    a = abs(a) // g
    b = abs(b) // g
    return (s, a, b)

def mode(a, b):
    # retrun dict_key, arr_key
    if a == 0 and b == 0:
        return 0, 0
    if a == 0:
        return 'ab', 0
    if b == 0:
        return 'ab', 1
    x = fraction_taple(a, b)
    y = fraction_taple(-1 * b, a)
    if x > y:
        return x, 0
    else:
        return y, 1

MOD = 1000000007

if __name__ == '__main__':

    n = int(input())

    d = defaultdict(lambda: [0, 0])
    zero = 0
    for _ in range(n):
        a, b = list(map(int, input().split()))
        dkey, akey = mode(a, b)
        if dkey == 0:
            zero += 1
        else:
            d[dkey][akey] += 1
    #print('d') # debug
    #pp(d) # debug

    ans = 1
    for pair in d.values():
        tmp = pow(2, pair[0], MOD) - 1 + pow(2, pair[1], MOD) - 1 + 1
        ans *= tmp
    ans += zero - 1
    ans %= MOD
    #print('ans') # debug
    print(ans)

    #print('\33[32m' + 'end' + '\033[0m') # debug