##A407: Solution

'''
Define a funtion Y = RC(X,f) that implements residual coding of the numerical list X using the function f (defined for non-negative integers) as a model. Check it with the example on page T5.9. Define also a function X = RD(Y,f) that implements the corresponding decoding.
'''

def RC(X,f): return [X[n]-f(n+1) for n in range(len(X))]

def RD(Y,f): return [Y[n]+f(n+1) for n in range(len(Y))]

# Data of example T5.9
f = lambda n: n**2 - n + 41
X = [41,43,46,52,62,71,82,98,115,131]

Y = RC(X,f)
print('Residual coding of Data using f as a model: ', Y)
X1 = RD(Y,f)
print('Residual decoding of Y using f as a model: ',X1)

# Testing function
def test(message):
    T = X == X1
    message = 'Test '+ message+':'
    if T: print(message + ' Successful\n')
    else: print(message + ' Failed\n')

# Test 1 
test('RC and RD')



'''
Define similar functions Y = PC(X) and X = PD(Y) (predictive coding and decoding), where y[j] = x[j]-(x[j-2]+x[j-1])/2, with the convention that x[-2] = x[-1] = 0. Test them with some suitable examples.
'''

def PC(X):
   X = 2*[0]+X
   return [ X[j] - ( X[j-2]+X[j-1] )/2 for j in range(2,len(X))]

def PD(Y):
   #x[j] = y[j] +(x[j-2]+x[j-1])/2 
   X = [Y[0],Y[1]+Y[0]/2]   # initial two entries of X
   for j in range(2,len(Y)) :
       X += [Y[j] + ( X[j-2]+X[j-1] )/2 ]
   return X
    
    
##Tests
Y = PC(X)
print('Predictive coding of Data: ', Y)
X1 = PD(Y)
print('Predictive decoding Y: ', X1)

# Test 2 
test('PC and PD (1)')


# Data'
from math import sin, pi
X =sample(sin,15, 0,pi/2)
Y = PC(X)
print("Predictive coding of Data': ", round(Y,2))
X1 = PD(Y)
print('Predictive decoding Y: ', round(X1,2))

# Test 3 
test('PC and PD (2)')



