import numpy as np

def test_linearity(system, x1, x2, a, tol=1e-5):
    '''
    Run a test, using provided signals, to determine whether the system might be linear.

    @param:
    system - a callable object, e.g., a method
    x1 - an ndarray
    x2 - an ndarray of the same size as x1
    a - a scalar
    tol - consider two signals equal if the average abs difference is less than tol

    @return:
    True if y3=y1+a*y2, else False, where y3=system(x1+a*x2).
    Here "True" means the system might be linear, "False" means it definitely isn't.
    '''
    raise NotImplementedError("You need to write this!")

def test_timeinvariance(system, x, d, tol=1e-5):
    '''
    Run a test, using the provided signal, to determine whether the system might be time-invariant:
    Create a signal x2 that has the same shape as x, but x2[n]=x[n-d] for d<=n<len(x).
    Create y2=system(x2) and y=system(y), then test to see if y2[n]=y[n-d] for d<=n<len(y).
    If not, the system is not time-invariant; if so, it might be.

    @param:
    system - a callable object, e.g., a method
    x - an ndarray
    d - a positive integer
    tol - consider two signals equal if the average abs difference is less than tol

    @return:
    True if the system might be time-invariant, otherwise False.
    '''
    raise NotImplementedError("You need to write this!")
    
def test_causality(system, x, n, tol=1e-5):
    '''
    Run a test, using the provided signal, to determine whether the system might be causal:
    Check to see whether y[n]=y2[n], where
     - y[n] is generated using the entire x, including past and future parts
     - y2[n] is generated using only x[m] for m<=n.
    If y[n]=y2[n], then the system might be causal; if not, it's non-causal.

    @param:
    system - a callable object, e.g., a method
    x - an ndarray
    n - a positive integer
    tol - consider y[n] and y2[n] equal if the np.linalg.norm(y[n]-y2[n]) < tol

    @return:
    True if the system might be causal, False if it's konwn to be non-causal.
    '''
    raise NotImplementedError("You need to write this!")

def test_stability(system, signal):
    '''
    Run a test, using the provided signal, to determine whether the system might be stable:
    If max(abs(signal)) is finite but max(abs(system(signal))) is infinite, then 
    the system might be unstable, so this function should return False.
    If max(abs(signal)) is infinite or max(abs(system(signal))) is finite, then
    the system might be stable, so this function should return True.
    '''
    raise NotImplementedError("You need to write this!")
