from my_exceptions import *


#nuage=((1,1),(2,2),(3,3),(4,4),(5,5),(6,7),(7,9),(8,11),(9,13))

def first(x):
    return x[0]
#testee et fonctionne

def second(x):
    return x[1]
#testee et fonctionne

def add(x,y):
    return x+y
#testee et fonctionne

def square(x):
    return x*x


def xiyi(x):
    return first(x)*second(x)
#testee et fonctionne

def xi_square(x):
    a=first(x)
    return a*a
#testee et fonctionne


def sum_xi_square(x):
    return reduce(add,map(xi_square,x))
#testee et fonctionne


def sum_xiyi(x):
    return reduce(add,map(xiyi,x))
#teste et fonctionne

def sum_xi(x):
    return reduce(add,map(first,x))
#teste et fonctionne

def sum_yi(x):
    return reduce(add,map(second,x))
#teste et fonctionne


# A    a11 a12    A=((a11,a12),(a21,a22))
#      a21 a22
#
#B     b1         B=(b1,b2)
#      b2

def solve_linear2_2(A,b):
    det=A[0][0]*A[1][1]-A[0][1]*A[1][0]
    if det != 0:
        x=(b[0]*A[1][1]-A[0][1]*b[1])/det
        y=(b[1]*A[0][0]-A[1][0]*b[0])/det
        return (x,y)
    else:
        raise NonInversibleSystem, 'solve_linear2_2'




def lin_reg(Nuage):
    Sum_xi=sum_xi(Nuage)

    a11=sum_xi_square(Nuage)
    a21=Sum_xi
    a12=Sum_xi
    a22=len(Nuage)
    
    b1=sum_xiyi(Nuage)
    b2=sum_yi(Nuage)
    
    coeff=solve_linear2_2(((a11,a12),(a21,a22)) ,(b1,b2))
    
    return coeff



def moindre_carre(Nuage,coefficient):
    def ecart_carre(x): return square(second(x)-(coefficient[0]*first(x)+coefficient[1]))    
    return reduce(add,map(ecart_carre,Nuage))




class Double_Linear_Regression:
    "Module to approximate a plot by the two best line"

    def __init__(self,plot):
        self.Plot=plot
        self.double_lin_reg()
        
        

    def double_lin_reg(self):
        min="infinity"
        for i in range(2,len(self.Plot)-2):
            coefficient1=lin_reg(self.Plot[0:i])
            coefficient2=lin_reg(self.Plot[i:len(self.Plot)])
            ecart=moindre_carre(self.Plot[0:i],coefficient1)+moindre_carre(self.Plot[i:len(self.Plot)],coefficient2)
            if ecart<min:
                coefficient=(coefficient1,coefficient2)
                min=ecart
        self.Coefficient=coefficient
        
	
    def coefficient(self):
        #        return self.double_lin_reg()
        return self.Coefficient
 

