from coreUtils import *
from couenneUtils import *

import cvxpy

import os

## Utils that will be imported using exec
#this way all variables that seem to be undefined are known.
#These are like template functions in c++

#NOTE: The variable set denoted Y in the article corresponds to xz

##########################

#iMA is a matrices holding the variable indices:
#
#      |1, x.T, z.T |
#iMA = |x,  X ,  Y  |
#      |z, Y.T,  Z  |
#

####
#Helpers for speed up
nxz = int(len(np.unique(iMA[1:1+nx,1+nx:].reshape((-1,)))))
iMAonlyOnce = -np.ones_like(iMA)
checked = []
for i in range(iMA.shape[0]):
    for j in range(i,iMA.shape[0]):
        k = iMA[i,j]
        if k in checked:
            continue
        checked.append(k)
        thisId = np.where(iMA==k)
        iMAonlyOnce[i,j] = k
##########################

#Cython utils depending on actual prob
toVecInd = lambda X, Ind, nMax=numVars: (toVecI(X,Ind)[:nMax]).reshape((nMax,1))
toMatInd = lambda x, Ind=iMA: toMatI(x.squeeze(), Ind)

#Function to calculate product constraints where both sets contain only
#constraints linear in x
getRLTxxCyWrap = lambda A1x, b1x, A2x=np.zeros((0,0)), b2x=np.zeros((0,0)): getRLTxxCy(A1x, b1x, A2x, b2x, iMa=iMA, nx=nx)

#Functions to calculate product constraints where the first set contains only
#constraints linear in x
noCstr = np.zeros((0,0))
#and the second constraint linear in x \cup X (linear and quadratic in x)
getRLTxXCyWrap = lambda A1x=noCstr, b1x=noCstr, A1X=noCstr, b1X=noCstr, A2x=noCstr, b2x=noCstr, A2X=np.zeros((0,0)), b2X=np.zeros((0,0)):  lmap( lambda Al: [np.vstack(Al[0]), np.vstack(Al[1])], getRLTGeneralCy(A1x, b1x, A1X, b1X, A2x, b2x, A2X, b2X, iMa=iMA, iMa1=np.zeros((0,0)).astype(np.int_), iMX2z=np.zeros((0,0)).astype(np.int_), nx=nx, nX=nX, nxz=nxz,types1=np.array([1,2]).astype(np.int_), types2=np.array([1,2]).astype(np.int_)) )
#and the second constraint set linear in x \cup X \cup Y (linear, quadratic und cubic in x)
getRLTxxzCyWrap = lambda A1x=noCstr, b1x=noCstr, A1X=noCstr, b1X=noCstr, A2x=noCstr, b2x=noCstr, A2X=np.zeros((0,0)), b2X=np.zeros((0,0)): lmap( lambda Al: [np.vstack(Al[0]), np.vstack(Al[1])], getRLTGeneralCy(A1x, b1x, A1X, b1X, A2x, b2x, A2X, b2X, iMa=iMA, iMa1=iMAonlyOnce, iMX2z=iMX2z, nx=nx, nX=nX, nxz=nxz, types1=np.array([1,3]).astype(np.int_), types2=np.array([1,3]).astype(np.int_)) )

#getSpecifiedRLT( A1,  b1,  A2, b2, iMa, iMa1, iMX2z, nx, nX, types):
getSpecifiedRLTCyWrap = lambda A1, b1, A2=np.zeros((0,0)), b2=np.zeros((0,0)), types=None: lmap( lambda a: np.asarray(a),  getSpecifiedRLT(A1, b1, A2, b2, iMa=iMA, iMa1=iMAonlyOnce, iMX2z=iMX2z, nx=nx, nX=nX, nxz=nxz, types = np.array(types).squeeze().astype(np.int_) ) )
##########################
def getPoly(x):
    #Get the value of the new variables
    x = x.reshape((nx,1))
    X = np.dot(x,x.T)
    z = np.vstack((x,toVec(X)))
    Y = np.identity(1+z.size)
    Y[0,1:] = z.squeeze()
    Y[1:,0] = z.squeeze()
    Y[1:,1:] = np.dot(z,z.T)
    YVec = toVecInd(Y,iMA)

    return YVec, Y
##########################

def checkResult(xSol):
    #Get the difference between exact and relaxed solution
    xe = xSol[:nx]
    Xe = np.dot(xe, xe.T)
    ze = np.zeros((nx*(nx+1)//2,1))
    nZ = 0
    for i in range(nx):
        for j in range(i,nx):
            ze[nZ] = Xe[i,j]
            nZ+=1
    Ze = np.dot(ze, ze.T)
    ZeTilde = np.dot( np.vstack((xe,ze)), np.vstack((xe,ze)).T )

    XSol = xSol[iMZt[:nx,:nx].reshape((-1,))].reshape((nx,nx))
    ZSol = xSol[iMZt[nx:,nx:].reshape((-1,))].reshape((nZ,nZ))
    ZtildeSol = xSol[iMZt.reshape((-1,))].reshape(iMZt.shape)

    deltaZtilde = ZtildeSol - ZeTilde
    eigDeltaX = np.linalg.eigvalsh(XSol-Xe)
    eigDeltaZ = np.linalg.eigvalsh(ZSol-Ze)
    eigDeltaZtilde = np.linalg.eigvalsh(ZtildeSol-ZeTilde)
    print('Difference Matrix:')
    print(deltaZtilde)
    print('eigVals:')
    print(eigDeltaX)
    print(eigDeltaZ)
    print(eigDeltaZtilde)

    return deltaZtilde, eigDeltaX, eigDeltaZ, eigDeltaZtilde

#####################################################################

def doSortIndices(A):
    #Function to classify constraints / determine their highest order
    iX = np.unique( iMA[0,1+nx:] )
    ixz = np.unique( iMA[1:1+nx, 1+nx:] )
    iZ =  np.unique( iMA[1+nx:, 1+nx:] )

    indX = np.any(np.abs(A[:,iX])>1e-13 , 1)
    indxz = np.any(np.abs(A[:,ixz])>1e-13 , 1)
    indZ = np.any(np.abs(A[:,iZ])>1e-13 , 1)

    #indOutx = np.logical_not( np.logical_or.reduce([indX, indxz, indZ]) )
    #indOutX = np.logical_and.reduce([np.logical_not( np.logical_or.reduce([indxz, indZ]) ), indX])
    #indOutxz = np.logical_and.reduce([np.logical_not( indZ ), indxz])
    #indoutZ = indZ

    return np.where(np.logical_not( np.logical_or.reduce([indX, indxz, indZ]) ))[0], np.where(np.logical_and.reduce([np.logical_not( np.logical_or.reduce([indxz, indZ]) ), indX]))[0], np.where(np.logical_and.reduce([np.logical_not( indZ ), indxz]))[0], np.where(indZ)[0]

################################################################################

def crtGeneralRLTPolyMin(A, B):
    #Pure python implementation
    #of product constraints. Rather slow but no presorting needed
    #TBD this needs to be improved

    N = A.shape[1]
    L = A.shape[0]
    M = L*(L+1)//2
    Aout = np.zeros((M,N))
    Bout = np.zeros((M,1))

    ZInd = iMA[1+nx:,1+nx:].reshape((-1,))
    xzInd = np.unique(iMA[1:1+nx:,1+nx:].reshape((-1,)))
    XxzInd = iMA[1:1+nx:,1:].reshape((-1,))
    ind = 0
    for k in range(L):
        for l in range(k,L):

            ak = -A[k,:]
            al = -A[l,:]
            bk =  B[k]
            bl =  B[l]

            if (np.any(np.abs(ak[ZInd]) > 1e-13) or np.any(np.abs(al[ZInd]) > 1e-13)):
                #Z*Z can not be represented
                continue
            if ((np.any(np.abs(ak[xzInd]) > 1e-13) and np.any(np.abs(al[XxzInd]) > 1e-13)) or (np.any(np.abs(al[xzInd]) > 1e-13) and np.any(np.abs(ak[XxzInd]) > 1e-13))):
                #xz*xz, X*xz can not be represented, x*xz can
                continue

            Aout[ind,:] = 0
            #Linear terms -> ALin = bk*al+bl*ak
            Aout[ind,:] = bk*al+ak*bl
            #terms in x and X
            for i in range(nx+nX):
                for j in range(nx+nX):
                    Aout[ind, iMA[1+i,1+j]] += ak[iMA[0,1+i]]*al[iMA[1+j,0]]

            doxz = False
            if np.any(np.abs(ak[xzInd]) > 1e-13):
                axz = ak
                ax = al
                doxz = True
            elif np.any(np.abs(al[xzInd]) > 1e-13):
                axz = al
                ax = ak
                doxz = True

            #All that is left to treat is the term x*xz
            #x_i*x_j*z_a -> z_b*z_a = Z_ab
            if doxz:
                for ix0 in range(nx):
                    checkedVars = []
                    #ix0 covers all linear terms of one constraint
                    #Take care that no terms appear twice
                    #This is probably the worst part, do differently
                    for ix1 in range(nx):
                        for j in range(nX):
                            thisXZvar = iMA[1+ix1,1+nx+j]
                            if thisXZvar in checkedVars:
                                continue
                            checkedVars.append(thisXZvar)
                            a = iMX2z[ix0,ix1]
                            Aout[ind, iMA[1+nx+a, 1+nx+j]] += ax[iMA[0,1+ix0]]*axz[thisXZvar]

            #Constant term
            Bout[ind] = bk*bl
            ind += 1

    #Delete unused
    Aout = Aout[:ind,:]
    Bout = Bout[:ind,0].reshape((ind,1))
    #Switch sign to conform with cvx
    Aout = -Aout

    #Append original cstr
    #Aout = np.vstack((A, Aout))
    #Bout = np.vstack((B, Bout))

    return Aout, Bout

#####################################################################
def crtGeneralRLTPolyMin2(A, B):
    #Differing in some implementation details from crtGeneralRLTPolyMin
    #TBD this needs to be improved

    N = A.shape[1]
    L = A.shape[0]
    M = L*(L+1)//2
    Aout = np.zeros((M,N))
    Bout = np.zeros((M,1))

    ZInd = iMA[1+nx:,1+nx:].reshape((-1,))
    xzInd = np.unique(iMA[1:1+nx:,1+nx:].reshape((-1,)))
    XxzInd = iMA[1:1+nx:,1:].reshape((-1,))
    ind = 0
    for k in range(L):
        for l in range(k,L):

            ak = -A[k,:]
            al = -A[l,:]
            bk =  B[k]
            bl =  B[l]

            if (np.any(np.abs(ak[ZInd]) > 1e-13) or np.any(np.abs(al[ZInd]) > 1e-13)):
                #Z*Z can not be represented
                continue
            if ((np.any(np.abs(ak[xzInd]) > 1e-13) and np.any(np.abs(al[XxzInd]) > 1e-13)) or (np.any(np.abs(al[xzInd]) > 1e-13) and np.any(np.abs(ak[XxzInd]) > 1e-13))):
                #xz*xz, X*xz can not be represented, x*xz can
                continue

            Aout[ind,:] = 0
            #Linear terms -> ALin = bk*al+bl*ak
            Aout[ind,:] = bk*al+ak*bl
            #terms in x and X
            for i in range(nx+nX):
                for j in range(nx+nX):
                    Aout[ind, iMA[1+i,1+j]] += ak[iMA[0,1+i]]*al[iMA[1+j,0]]

            doxz = False
            if np.any(np.abs(ak[xzInd]) > 1e-13):
                axz = ak
                ax = al
                doxz = True
            elif np.any(np.abs(al[xzInd]) > 1e-13):
                axz = al
                ax = ak
                doxz = True

            #All that is left to treat is the term x*xz
            #x_i*x_j*z_a -> z_b*z_a = Z_ab
            if doxz:
                for ix0 in range(nx):
                    #ix0 covers all linear terms of one constraint
                    #Take care that no terms appear twice
                    #This is probably the worst part, do differently
                    for ix1 in range(nx):
                        for j in range(nX):
                            thisXZvar = iMAonlyOnce[1+ix1,1+nx+j]
                            if thisXZvar == -1:
                                continue
                            a = iMX2z[ix0,ix1]
                            Aout[ind, iMA[1+nx+a, 1+nx+j]] += ax[iMA[0,1+ix0]]*axz[thisXZvar]

            #Constant term
            Bout[ind] = bk*bl
            ind += 1

    #Delete unused
    Aout = Aout[:ind,:]
    Bout = Bout[:ind,0].reshape((ind,1))
    #Switch sign to conform with cvx
    Aout = -Aout

    #Append original cstr
    #Aout = np.vstack((A, Aout))
    #Bout = np.vstack((B, Bout))

    return Aout, Bout

#####################################################################
def doSortMatrices(A, B):

    iix, iiX, iixz, iiZ = doSortIndices(A)

    Ax = A[iix, :]
    Bx = B[iix]

    AX = A[iiX, :]
    BX = B[iiX]

    Axz = A[iixz, :]
    Bxz = B[iixz]

    AZ = A[iiZ, :]
    BZ = B[iiZ]

    return Ax, Bx, AX, BX, Axz, Bxz, AZ, BZ

#####################################################################

def getRLTxx(Ax, Bx ):
    #Improved pure python implementation for constraints C_x \otimes C_x
    Lx, N = Ax.shape

    ix = iMA[0,1:1+nx]

    Axx = np.zeros((Lx*(Lx+1)//2,N))
    Bxx = np.zeros((Lx*(Lx+1)//2,1))

    #Do x \wedge x
    indStore = 0
    #a0.x <= b0
    #a1.x <= b1
    #->
    #(a0*x-b0)*(a1*x-b1)<=0
    #a0*a1*x*x - b1*a0*x - b0*a1*x  + b0*b1 <= 0
    #a0*a1*x*x - b1*a0*x - b0*a1*x <= -b0*b1

    for k in range(Lx):
        indAdd = Lx-k
        nNewCstr=Lx-k
        indNewCstr = np.arange(k,Lx)
        indNewStore = np.arange(indStore, indStore+indAdd)

        #Multiplied by scalar terms so - b1*a0*x - b0*a1*x
        Axx[np.ix_(indNewStore, ix)] = - Bx[k]*Ax[np.ix_(indNewCstr, ix)] - np.multiply( np.broadcast_to(Bx[indNewCstr], (nNewCstr,nx)), np.broadcast_to(Ax[k,ix], (nNewCstr,nx)) )

        #Get the quadratic terms a0*a1*x*x
        for i in range(nx):
            ii = iMA[0,1+i]
            #get a_0ii*x_ii*a_1ii*x_ii
            Axx[indNewStore, iMA[1+i,1+i]] += Ax[k,ii]*Ax[indNewCstr,ii]

        for i in range(nx):
            for j in range(i+1,nx):
                #get a_0i*x_i*a_1j*x_j + a_0j*x_j*a_1i*x_i
                Axx[indNewStore, iMA[1+i,1+j]] += Ax[k,iMA[0,1+i]]*Ax[indNewCstr, iMA[0,1+j]] + Ax[k,iMA[0,1+j]]*Ax[indNewCstr, iMA[0,1+i]]

        #Get the B with correct sign -b0*b1
        Bxx[indNewStore] = Bx[k]*Bx[indNewCstr]
        #increment
        indStore += indAdd

    Axx=-Axx

    return Axx, Bxx

#####################################################################

def crtGeneralRLTPolyMinSortedAll(Ax, Bx, AX=None, BX=None, Axz=None, Bxz=None):
    #Pure python implementation to get product constraints for sorted constraint sets
    zzA = np.zeros((0,Ax.shape[1]))
    zzB = np.zeros((0,1))

    AX = AX if not(AX is None) else zzA
    Axz = Axz if not(Axz is None) else zzA
    BX = BX if not(BX is None) else zzB
    Bxz = Bxz if not(Bxz is None) else zzB

    #Lazy Mans way for the moment before implementing better versions
    getRLTxX = getRLTxxz = getRLTXX = lambda Axi, Bxi, AXi, BXi, *args: crtGeneralRLTPolyMin(np.vstack((Axi,AXi)), np.vstack((Bxi,BXi)))

    #Set of x \otimes x
    Axx, Bxx = getRLTxx(Ax, Bx )

    #Set of x \otimes X
    AxX, BxX = getRLTxX(Ax, Bx, AX, BX )

    #Set of x \otimes ( x \wedge x )
    Axxx, Bxxx = getRLTxX(Ax, Bx, Axx, Bxx )

    #Set of x \otimes xz
    Axxz, Bxxz = getRLTxxz(Ax, Bx, Axz, Bxz )

    #Set of x \otimes ( x \wedge X)
    Ax0xX, Bx0xX = getRLTxxz(Ax, Bx, AxX, BxX ) #Produces a lot of cstrs

    #Set of ( x \otimes  x ) \wedge X
    Axx0X, Bxx0X = getRLTXX(Axx, Bxx, AX, BX )

    #Set of X \otimes X
    AXX, BXX = getRLTXX(AX, BX, AX, BX )

    #Set of X \otimes X
    Axxxx, Bxxxx = getRLTXX(Axx, Bxx, Axx, Bxx ) #Produces a lot of cstrs

    return  [Axx], [AxX, Axxx], [Axxz, Ax0xX, Axx0X, AXX, Axxxx], [Bxx], [BxX, Bxxx], [Bxxz, Bx0xX, Bxx0X, BXX, Bxxxx]

#####################################################################

def crtGeneralRLTPolyMinSortedAllCy(Axin, Bxin, AXin=None, BXin=None, Axzin=None, Bxzin=None):
    #Efficient cython based implementation of product constraints.
    #Attention: It is not verified whether Axin contains only constraints in x etc.
    #Results are false if this is not true
    zzA = np.zeros((0,Axin.shape[1]))
    zzB = np.zeros((0,1))

    AXin = AXin if not(AXin is None) else zzA
    Axzin = Axzin if not(Axzin is None) else zzA
    BXin = BXin if not(BXin is None) else zzB
    Bxzin = Bxzin if not(Bxzin is None) else zzB

    #Atest,Btest = getSpecifiedRLTCyWrap(Axin[[0],:], Bxin[[0],:], Axzin[[0],:], Bxzin[[0],:], [1,3])
    #Atest0,Btest0 = crtGeneralRLTPolyMin2(np.vstack((Axin[[0],:],Axzin[[0],:])), np.vstack((Bxin[[0],:],Bxzin[[0],:])))

    #Set of (x, X) \wedge (x, X)
    [Axx, Bxx], [AxX, BxX], [AXX,BXX] = getRLTxXCyWrap(Axin, Bxin, AXin, BXin )

    #Set of x \wedge ( x \wedge x )
    #[_,_],[Axxx, Bxxx],[_,_] = getRLTxXCyWrap(Axin, Bxin, A2X=Axx, b2X=Bxx )
    Axxx, Bxxx = getSpecifiedRLTCyWrap(Axin, Bxin, Axx, Bxx, [1,2])

    #Set of x \wedge xz
    #[_,_],[Axxz, Bxxz],[_,_] = getRLTxxzCyWrap(Axin, Bxin, A2X=Axzin, b2X=Bxzin )
    Axxz, Bxxz = getSpecifiedRLTCyWrap(Axin, Bxin, Axzin, Bxzin, [1,3])

    #Set of x \wedge ( x \wedge X)
    #[_,_],[Ax0xX, Bx0xX],[_,_] = getRLTxxzCyWrap(Axin, Bxin, A2X=AxX, b2X=BxX ) #Produces a lot of cstrs
    Ax0xX, Bx0xX = getSpecifiedRLTCyWrap(Axin, Bxin, AxX, BxX, [1,3])

    #This can be done in one call

    #Set of ( x \wedge  x ) \wedge X
    #[_,_],[_,_],[Axx0X, Bxx0X] = getRLTxXCyWrap(A1X=Axx, b1X=Bxx, A2X=AXin, b2X=BXin )
    Axx0X, Bxx0X = getSpecifiedRLTCyWrap(Axx, Bxx, AXin, BXin, [2,2] )

    #Set of X \wedge X
    #[_,_],[_,_],[AXX, BXX] = getRLTxXCyWrap(A1X=AX, b1X=BX )
    #AXXin, BXXin = getSpecifiedRLTCyWrap(AXin, BXin, [2,2] )

    #Set of X \wedge X
    #[_,_],[_,_],[Axxxx, Bxxxx] = getRLTxXCyWrap(A1X=Axx, b1X=Bxx ) #Produces a lot of cstrs
    Axxxx, Bxxxx = getSpecifiedRLTCyWrap(Axx, Bxx, types=[2,2])

    return  [Axx], [AxX, Axxx], [Axxz, Ax0xX, Axx0X, AXX, Axxxx], [Bxx], [BxX, Bxxx], [Bxxz, Bx0xX, Bxx0X, BXX, Bxxxx]

#####################################################################
def crtGeneralRLTPolyMinSortedAddLinCy(Axp, Bxp, Ax, Bx, AX=None, BX=None, Axz=None, Bxz=None):
    #An efficient implementation of adding a set of constraints linear in x (i.e. the partitionning of the state-space)
    #to sets of existing constraints and computing all possible product constraints
    zzA = np.zeros((0,Ax.shape[1]))
    zzB = np.zeros((0,1))

    AX = AX if not(AX is None) else zzA
    Axz = Axz if not(Axz is None) else zzA
    BX = BX if not(BX is None) else zzB
    Bxz = Bxz if not(Bxz is None) else zzB

    #Set of (x, xp) \wedge (xp)
    [Axxp, Bxxp], [Axpxp, Bxpxp], [_,_] = getRLTxXCyWrap(A1x=Ax, b1x=Bx, A1X=Axp, b1X=Bxp, A2x=Axp, b2x=Bxp )

    #getSpecifiedRLT( A1,  b1,  A2, b2, types):
    #Set of x \wedge xp \wedge (xp)
    Axxpxp,Bxxpxp = getSpecifiedRLTCyWrap(Axp, Bxp, Axxp, Bxxp, [1,2])
    #Set of x \wedge xp \wedge (xp)
    Axpxpxp,Bxpxpxp = getSpecifiedRLTCyWrap(Axp, Bxp, Axpxp, Bxpxp, [1,2])

    #Set of x \wedge x \wedge xp #IS equal to (??) X \wedge xp
    AXxp,BXxp = getSpecifiedRLTCyWrap(Axp, Bxp, AX, BX, [1,2])

    #Set xp \wedge [xz, Xxp, xxpxp, xpxpxp]
    AdivZ1, BdivZ1 = getSpecifiedRLTCyWrap(Axp, Bxp, np.vstack([Axz,AXxp,Axxpxp,Axpxpxp]), np.vstack([Bxz,BXxp,Bxxpxp,Bxpxpxp]), [1,3])

    #Set x \wedge Xxp
    AXxpx, BXxpx = getSpecifiedRLTCyWrap(Ax, Bx, AXxp, BXxp, [1,3])

    return  [Axxp, np.vstack([Axxpxp, Axpxpxp, AXxp]), np.vstack([AdivZ1, AXxpx])], [Bxxp, np.vstack([Bxxpxp, Bxpxpxp, BXxp]), np.vstack([BdivZ1, BXxpx])]

#####################################################################
def getRedundInd( inList ):
    #Get a list of numerically identitical constraints
    A, indList = inList

    indList.squeeze()

    identicalCstr = [ [] for _ in range(indList.size) ]

    for k, aInd in enumerate(indList):
        identicalCstr[k] = np.where(np.all(np.abs( A - A[aInd,:] ) < 1e-10, 1))[0]

    return identicalCstr

#####################################################################
def noRedundCstrApprox2(A, b, c=None, indList = None, nx=None, iMa=None):
    #get an heuristic approximation of the nonredudant constraint set
    #Partially taken from noredund from matlabcentral
    #It computes the "most" constraining constraints by computing
    #the dual polytope and use vertices "far away" from the origin
    L = A.shape[0]
    N = A.shape[1]

    if (not (c is None)):
        c = np.array(c).reshape((-1,1))

    if ( (c is None) or np.any( np.dot( A, c ) > b )):
        #Non c or inappriopriate c given
        Atilde = np.hstack(( np.ones((L,1)), A ))

        obj = matrix(0.0, (N+1,1))
        obj[0] = -1.

        solLP = solvers.lp( obj, G=sparse(matrix(Atilde)), h=matrix(b) )

        c = np.array(solLP['x'][1:]).reshape((-1,1))

    # move polytope to contain origin
    bk = b.copy() # preserve
    b = b - np.dot(A,c) # polytope A*x <= b now includes the origin
    # obtain dual polytope vertices: Simply use min max in each direction as approx
    D = np.divide(A , np.tile(b,[1, N]))
    #limMinI = np.argmin(D, axis=0)
    #limMaxI = np.argmax(D, axis=0)

    #nr = np.unique( np.hstack(( limMinI, limMaxI )) )
    if indList is None:
        indList = doSortIndices(A, nx, iMa)

    taskList = zip( len(indList)*[D], indList )

    if glbDBG:
        identicalCstr = list(map(getRedundInd, taskList))
    else:
        #The parallelisation needs to be changed to pipe
        identicalCstr = list(map(getRedundInd, taskList))

    identicalCstr = list(itertools.chain.from_iterable(identicalCstr))

    nr = np.unique(np.array(list(map( lambda aInd: aInd[0], identicalCstr ))))

    An=A[nr,:]
    bn=bk[nr]

    return An, bn, nr

############################################

#Construct the upper and lower bounds for each element in the new variable set
#This function depends on couenne to work. However for the example problems they are precomputed
from couenneUtils import *
#AlimUpLowx, BlimUpLowx, AlimUpLowX, BlimUpLowX, AlimUpLowxz, BlimUpLowxz, AlimUpLowZ, BlimUpLowZ = boundCalculator( self.nx, (self.nx*(self.nx+1))//2, self.numVars, self.iMx, self.iMZt, self.powerxz, self.powerZtilde, mode = 'SDR')
def getBounds( mode = 'SDR', doRecompute = False ):
    #Since they are always the same its worth storint them
    thisName = '../varBounds/RES_{0:d}_{1:d}_{2:d}_{3}.pickle'.format(nx, nX, numVars, mode)
    if not doRecompute:
        try:
            with open(thisName, 'rb') as f:
                sol = pickle.load(f)
            return sol['AlimUpLowx'], sol['BlimUpLowx'], sol['AlimUpLowX'], sol['BlimUpLowX'], sol['AlimUpLowxz'], sol['BlimUpLowxz'], sol['AlimUpLowZ'], sol['BlimUpLowZ']
        except:
            print('Either recomputing or new demand')

    ABBcouenne = np.vstack(( np.identity(nx), -np.identity(nx) ))
    PsphereCouenne = np.identity(nx)
    assert  mode in ('SDR', 'DNN'), 'either SDR or DNN'
    if mode == 'SDR':
        BBBcouenne = np.ones((2*nx,1))
        LsphereCouenne = np.zeros((nx,1))
        csphereCouenne = 1.0
        xU = 1.
        xL = -1.
        XDU = 1.0
        XDL = 0.0
        XOU = 0.5
        XOL = -0.5
    elif mode == 'DNN':
        BBBcouenne = np.vstack(( np.ones((nx,1)), np.zeros((nx,1)) ))
        LsphereCouenne = -np.ones((nx,1))
        csphereCouenne = (1.0-nx)/4.
        xU = 1.
        xL = 0.
        XDU = 1.0
        XDL = 0.0
        XOU = 0.5+0.5/2**0.5
        XOL = 0.

    limLower = np.zeros((numVars,))
    limUpper = np.zeros((numVars,))

    AlimUpLowx = np.zeros(( 2*nx, numVars ))
    BlimUpLowx = np.zeros(( 2*nx, 1 ))
    indx = 0
    AlimUpLowX = np.zeros(( 2*nX, numVars ))
    BlimUpLowX = np.zeros(( 2*nX, 1 ))
    indX = 0
    AlimUpLowxz = np.zeros(( 2*nx*nX, numVars ))
    BlimUpLowxz = np.zeros(( 2*nx*nX, 1 ))
    indxz = 0
    AlimUpLowZ = np.zeros(( 2*(nX*(nX+1)//2), numVars ))
    BlimUpLowZ = np.zeros(( 2*(nX*(nX+1)//2), 1 ))
    #AlimUpLowZ = np.zeros(( 2*(NProb-nx*nx-nx-nx), NProb ))
    #BlimUpLowZ = np.zeros(( 2*(NProb-nx*nx-nx-nx), 1 ))
    indZ = 0
    #x
    for k in range(nx):
        limUpper[iMx[k]] = xU
        limLower[iMx[k]] = xL
        AlimUpLowx[indx, iMx[k]]  = 1.
        BlimUpLowx[indx]  = limUpper[iMx[k]]
        AlimUpLowx[indx+1, iMx[k]]  = -1.
        BlimUpLowx[indx+1]  = -limLower[iMx[k]]
        indx += 2

    #X vec(X)=z
    for i in range(nx):
        for j in range(i,nx):
            if i==j:
                limUpper[iMZt[i,j]] = XDU
                limLower[iMZt[i,j]] = XDL
            else:
                limUpper[iMZt[i,j]] = XOU
                limLower[iMZt[i,j]] = XOL
            AlimUpLowX[indX, iMZt[i,j]]  = 1.
            BlimUpLowX[indX]  = limUpper[iMZt[i,j]]
            AlimUpLowX[indX+1, iMZt[i,j]]  = -1.
            BlimUpLowX[indX+1]  = -limLower[iMZt[i,j]]
            indX += 2

    #Without redundancy in x.z
    checkedVars = []
    for i in range(nx):
        for j in range(nX):
            thisVar = iMZt[i,nx+j]
            if thisVar in checkedVars:
                continue
            checkedVars.append(thisVar)
            #Min
            thisCInst = couenneInst()
            for k in range(nx):
                thisCInst.addVar()
            thisCInst.addQuadCstr(PsphereCouenne, LsphereCouenne, csphereCouenne)
            thisCInst.addLinCstr(ABBcouenne, BBBcouenne)
            thisCInst.addObjMono(relaxationClass.powerZtilde[i][nx+j], 'MIN')
            objective, varsVal, solTime = thisCInst.solve()
            limLower[iMZt[i,nx+j]] = objective[0]

            #Max
            thisCInst = couenneInst()
            for k in range(nx):
                thisCInst.addVar()
            thisCInst.addQuadCstr(PsphereCouenne, LsphereCouenne, csphereCouenne)
            thisCInst.addLinCstr(ABBcouenne, BBBcouenne)
            thisCInst.addObjMono(relaxationClass.powerZtilde[i][nx+j], 'MAX')
            objective, varsVal, solTime = thisCInst.solve()
            limUpper[iMZt[i,nx+j]] = objective[0]

            AlimUpLowxz[indxz, iMZt[i,nx+j]]  = 1.
            BlimUpLowxz[indxz]  = limUpper[iMZt[i,nx+j]]
            AlimUpLowxz[indxz+1, iMZt[i,nx+j]]  = -1.
            BlimUpLowxz[indxz+1]  = -limLower[iMZt[i,nx+j]]
            indxz += 2
    #Delete unnecessary:
    AlimUpLowxz = AlimUpLowxz[:indxz,:]
    BlimUpLowxz = BlimUpLowxz[:indxz]

    #new version
    checkedVars = []
    for i in range(nX):
        for j in range(i,nX):
            thisVar = iMZt[nx+i,nx+j]
            if thisVar in checkedVars:
                continue
            checkedVars.append(thisVar)
            #Min
            thisCInst = couenneInst()
            for k in range(nx):
                thisCInst.addVar()
            thisCInst.addQuadCstr(PsphereCouenne, LsphereCouenne, csphereCouenne)
            thisCInst.addLinCstr(ABBcouenne, BBBcouenne)
            thisCInst.addObjMono(relaxationClass.powerZtilde[nx+i][nx+j], 'MIN')
            objective, varsVal, solTime = thisCInst.solve()
            limLower[iMZt[nx+i,nx+j]] = objective[0]

            #Max
            thisCInst = couenneInst()
            for k in range(nx):
                thisCInst.addVar()
            thisCInst.addQuadCstr(PsphereCouenne, LsphereCouenne, csphereCouenne)
            thisCInst.addLinCstr(ABBcouenne, BBBcouenne)
            thisCInst.addObjMono(relaxationClass.powerZtilde[nx+i][nx+j], 'MAX')
            objective, varsVal, solTime = thisCInst.solve()
            limUpper[iMZt[nx+i,nx+j]] = objective[0]

            AlimUpLowZ[indZ, iMZt[nx+i,nx+j]]  = 1.
            BlimUpLowZ[indZ]  = limUpper[iMZt[nx+i,nx+j]]
            AlimUpLowZ[indZ+1, iMZt[nx+i,nx+j]]  = -1.
            BlimUpLowZ[indZ+1]  = -limLower[iMZt[nx+i,nx+j]]
            indZ += 2
    #Delete unnecessary:
    AlimUpLowZ = AlimUpLowZ[:indZ,:]
    BlimUpLowZ = BlimUpLowZ[:indZ]

    with open(thisName, 'wb') as f:
        pickle.dump({'AlimUpLowx':AlimUpLowx, 'BlimUpLowx':BlimUpLowx, 'AlimUpLowX':AlimUpLowX, 'BlimUpLowX':BlimUpLowX, 'AlimUpLowxz':AlimUpLowxz, 'BlimUpLowxz':BlimUpLowxz, 'AlimUpLowZ':AlimUpLowZ, 'BlimUpLowZ':BlimUpLowZ}, f)

    return AlimUpLowx, BlimUpLowx, AlimUpLowX, BlimUpLowX, AlimUpLowxz, BlimUpLowxz, AlimUpLowZ, BlimUpLowZ

############################################################
def NCrelaxCalcDirect( dictLin, dictPoly, **kwargs):
    #Do the actual optimization.
    #minimize the linear functional corresponding the best obtainable derivative of
    #the Lyapunov function subject to LMI constraints
    #NCrelaxCalcDirect does this in one shot by taking into account all
    #linear constraints obtainable

    #numVars, degrees2ind, AcstrBase, BcstrBase, indMatrixAll, indMatrixZtilde, indMatrixXtoz, nx, firstCond, secondCond = addInputs
    #The LMI constraints corresponding to
    #|1, x.T|
    #|x, X  | >> 0
    #and
    #|1, x.T, z.T|
    #|x,  X , Y  | >> 0
    #|z, Y.T, Z  |

    allCond = [relaxationClass.firstCond, relaxationClass.secondCond]

    try:
        allCond.append(relaxationClass.thirdCond)
        #Third valid LMI constraint which is redundant but sometimes improves convergence
        #|X  , Y  |
        #|Y.T, Z  | >> 0

    except:
        pass

    allCondA = lmap(lambda a: a[0], allCond)
    allCondB = lmap(lambda a: a[1], allCond)
    otherDict = {}
    otherDict.update(kwargs)

    if 'linearCstr' in otherDict.keys():
        #2 Set up all the constraints

        #New way for creating the RLTs
        #Add the constraints for state-space partitioning and get the products
        ARLTList, BRLTList = crtGeneralRLTPolyMinSortedAddLinCy(Axp=otherDict['linearCstr'][0], Bxp=otherDict['linearCstr'][1], Ax=relaxationClass.AtildeCstrBasex, Bx=relaxationClass.BtildeCstrBasex, AX=relaxationClass.AtildeCstrBaseX, BX=relaxationClass.BtildeCstrBaseX, Axz=relaxationClass.AtildeCstrBasexz, Bxz=relaxationClass.BtildeCstrBasexz)
        AallCstr = np.vstack( [relaxationClass.AtildeCstrBase]+ARLTList )
        BallCstr = np.vstack( [relaxationClass.BtildeCstrBase]+BRLTList )
    else:
        assert 0, 'nope'

    #1 get the objective
    #CVXopt minimizes. but we want to maximize
    #Objective function corresponds to the linearised version of the fourth
    #order polynomial
    objFun = np.zeros((numVars,1))
    for deg, degval in dictLin.items():
        objFun[relaxationClass.deg2ind[deg]] += degval
    for deg, degval in dictPoly.items():
        objFun[relaxationClass.deg2ind[deg]] += degval
    objFun = -objFun

    #Solve
    nQuad = nx*(nx+1)//2
    NNN=0

    #Approximate solve
    #Scale the objective because otherwise its fails sometimes
    scaleFac = np.max(np.abs(objFun))
    objFun = objFun/scaleFac

    #Get the sparse representation
    AallCstr = sparse(matrix(AallCstr))
    BallCstr = matrix(BallCstr)

    #TBD do we need to scale cstrs too?
    sol = solvers.sdp(matrix(objFun), Gl=AallCstr, hl=BallCstr, Gs=allCondA, hs=allCondB)
    assert sol['status']=='optimal', "Optimization failed on non-optimal points"

    #Test
    #Compare the relaxation result with the exact result
    #using couenne
    #solE,posE = exactSol(dictLin, dictPoly, **kwargs)
    #if -float(sol['primal objective'])*scaleFac < solE-1e-2:
    #    print('aaaaaaaaa')

    return -float(sol['primal objective'])*scaleFac, np.array(sol['x'])

############################################################

def NCrelaxCalcIter( dictLin, dictPoly, **kwargs):
    #Do the actual optimization.
    #minimize the linear functional corresponding the best obtainable derivative of
    #the Lyapunov function subject to LMI constraints
    #NCrelaxCalcIter uses a heuristic to determine linear constraint susceptible to be important
    #and then iterates adding violated constraints until either no new constraints
    #are violated or the found minimum is larger than 0 (equivalent to the convergence of the system)

    #numVars, degrees2ind, AcstrBase, BcstrBase, indMatrixAll, indMatrixZtilde, indMatrixXtoz, nx, firstCond, secondCond = addInputs
    allCond = [relaxationClass.firstCond, relaxationClass.secondCond]

    try:
        allCond.append(relaxationClass.thirdCond)
    except:
        pass

    allCondA = lmap(lambda a: a[0], allCond)
    allCondB = lmap(lambda a: a[1], allCond)
    otherDict = {}
    otherDict.update(kwargs)

    if 'linearCstr' in otherDict.keys():
        #2 Set up all the constraints
        if 0:
            AX, Axz, AZ, BX, Bxz, BZ = crtGeneralRLTPolyMinSortedAll(np.vstack((relaxationClass.AcstrBasex, otherDict['linearCstr'][0])), np.vstack((relaxationClass.BcstrBasex, otherDict['linearCstr'][1])), AX=relaxationClass.AcstrBaseX, BX=relaxationClass.BcstrBaseX, Axz=relaxationClass.AcstrBasexz, Bxz=relaxationClass.BcstrBasexz)
            AallCstr = np.vstack([relaxationClass.AcstrBase]+AX+Axz+AZ+[otherDict['linearCstr'][0]])
            BallCstr = np.vstack([relaxationClass.BcstrBase]+BX+Bxz+BZ+[otherDict['linearCstr'][1]])
            AminCstr, BminCstr, nrcor = noRedundCstrApprox(AallCstr, BallCstr)
        elif ('alpha' in otherDict.keys()) and ('polyCstr' in otherDict.keys()) and lyapReg.polyInputSep:
            assert not(otherDict['polyCstr'] is None), "polyCstr not given!"
            #The polynomials in polySet are, in general, already of order 4 -> No constraint product possible

            AallCstr = np.vstack( (relaxationClass.AtildeCstrBase, otherDict['polyCstr'][0]) )
            BallCstr = np.vstack( (relaxationClass.BtildeCstrBase, otherDict['polyCstr'][1]) )
            #We want a solution for x that points "the best possible" into the direction of all normals
            #So max sum_i n_i.x
            #with
            #x.T.P.x <= alpha
            #n_i.x>0
            #With y = C.x this is equal to
            # max sum n_i.C.y -> min sum nc_i.y which is given
            #||y||_2 <= alpha^2
            #-n_i.C.y <= 0 -> nc_i.y <= 0 which is given
            G = -matrix([matrix(0.0,(1,nx)), matrix(np.eye(nx))])
            h = matrix([np.sqrt(otherDict['alpha']),matrix(0.0,(nx,1))])
            Glin = otherDict['normalsSet']
            try:
                hlin = matrix(-otherDict['epsDeadZone'], (otherDict['normalsSet'].shape[0],1))
            except KeyError:
                hlin = matrix(-1.0e-4, (otherDict['normalsSet'].shape[0],1))

            obj = matrix(np.sum(Glin,0).reshape((-1,1)))
            Glin = matrix(Glin)

            if 0:
                solLPstandardSol = solvers.socp(c=obj, Gl=Glin, hl=hlin, Gq=[G], hq=[h])
                assert solLPstandardSol['status']=='optimal', 'Failed to find a LP solution'
                xStandard = np.array(solLPstandardSol['x']).reshape((-1,1))
            else:
                xcvxpy = cvxpy.Variable(nx,1)
                cstr1 = np.array(Glin)*xcvxpy <= np.array(hlin)
                cstr2 = cvxpy.norm(xcvxpy) <= np.sqrt(otherDict['alpha'])
                obj1 = cvxpy.Minimize( cvxpy.max_entries( otherDict['normalsSet']*xcvxpy ))
                prob = cvxpy.Problem(obj1, [cstr1, cstr2])
                prob.solve()
                assert prob.status == 'optimal',  'Failed to find a min solution'
                xStandard = np.array(xcvxpy.value)
                xStandard.resize((nx,1))

            xAllStandard, xAllStandardM = getPoly(xStandard)
            assert np.all( ndot(AallCstr, xAllStandard)<=BallCstr+1e-5 ), "Standard solution is violating a constraint"

            AminCstr, BminCstr, nrcor = noRedundCstrApprox(AallCstr, BallCstr, c=xAllStandard)

        elif ('alpha' in otherDict.keys()) and ('normalsSet' in otherDict.keys()):
            #Do a socp to find "ideal" point
            #AX, Axz, AZ, BX, Bxz, BZ = crtGeneralRLTPolyMinSortedAll(np.vstack((relaxationClass.AcstrBasex, otherDict['linearCstr'][0])), np.vstack((relaxationClass.BcstrBasex, otherDict['linearCstr'][1])), AX=relaxationClass.AcstrBaseX, BX=relaxationClass.BcstrBaseX, Axz=relaxationClass.AcstrBasexz, Bxz=relaxationClass.BcstrBasexz)
            #AallCstr = np.vstack([relaxationClass.AcstrBase]+AX+Axz+AZ+[otherDict['linearCstr'][0]])
            #BallCstr = np.vstack([relaxationClass.BcstrBase]+BX+Bxz+BZ+[otherDict['linearCstr'][1]])

            #New way for creating the RLTs
            ARLTList, BRLTList = crtGeneralRLTPolyMinSortedAddLinCy(Axp=otherDict['linearCstr'][0], Bxp=otherDict['linearCstr'][1], Ax=relaxationClass.AtildeCstrBasex, Bx=relaxationClass.BtildeCstrBasex, AX=relaxationClass.AtildeCstrBaseX, BX=relaxationClass.BtildeCstrBaseX, Axz=relaxationClass.AtildeCstrBasexz, Bxz=relaxationClass.BtildeCstrBasexz)
            AallCstr = np.vstack( [relaxationClass.AtildeCstrBase]+ARLTList )
            BallCstr = np.vstack( [relaxationClass.BtildeCstrBase]+BRLTList )
            #We want a solution for x that points "the best possible" into the direction of all normals
            #So max sum_i n_i.x
            #with
            #x.T.P.x <= alpha
            #n_i.x>0
            #With y = C.x this is equal to
            # max sum n_i.C.y -> min sum nc_i.y which is given
            #||y||_2 <= alpha^2
            #-n_i.C.y <= 0 -> nc_i.y <= 0 which is given
            G = -matrix([matrix(0.0,(1,nx)), matrix(np.eye(nx))])
            h = matrix([np.sqrt(otherDict['alpha']),matrix(0.0,(nx,1))])
            Glin = otherDict['normalsSet']
            try:
                hlin = matrix(-otherDict['epsDeadZone'], (otherDict['normalsSet'].shape[0],1))
            except KeyError:
                hlin = matrix(-1.0e-4, (otherDict['normalsSet'].shape[0],1))

            obj = matrix(np.sum(Glin,0).reshape((-1,1)))
            Glin = matrix(Glin)

            if 0:
                solLPstandardSol = solvers.socp(c=obj, Gl=Glin, hl=hlin, Gq=[G], hq=[h])
                assert solLPstandardSol['status']=='optimal', 'Failed to find a LP solution'
                xStandard = np.array(solLPstandardSol['x']).reshape((-1,1))
            else:
                xcvxpy = cvxpy.Variable(nx,1)
                cstr1 = np.array(Glin)*xcvxpy <= np.array(hlin)
                cstr2 = cvxpy.norm(xcvxpy) <= np.sqrt(otherDict['alpha'])
                obj1 = cvxpy.Minimize( cvxpy.max_entries( otherDict['normalsSet']*xcvxpy ))
                prob = cvxpy.Problem(obj1, [cstr1, cstr2])
                prob.solve()
                assert prob.status == 'optimal',  'Failed to find a min solution'
                xStandard = np.array(xcvxpy.value)
                xStandard.resize((nx,1))

            xAllStandard, xAllStandardM = getPoly(xStandard)
            assert np.all( ndot(AallCstr, xAllStandard)<=BallCstr+1e-5 ), "Standard solution is violating a constraint"

            AminCstr, BminCstr, nrcor = noRedundCstrApprox(AallCstr, BallCstr, c=xAllStandard)

        else:
            AallCstr, BallCstr = crtGeneralRLTPolyMin( np.vstack((relaxationClass.AcstrBase, otherDict['linearCstr'][0])), np.vstack((relaxationClass.BcstrBase, otherDict['linearCstr'][1])))
            AallCstr, BallCstr = np.vstack((relaxationClass.AcstrBase,AallCstr)), np.vstack((relaxationClass.BcstrBase,BallCstr))
            AminCstr, BminCstr, nrcor = noRedundCstrApprox(AallCstr, BallCstr)
    elif 'allCstr' in otherDict.keys():
        AallCstr, BallCstr, AminCstr, BminCstr, nrcor = otherDict['allCstr']

    #1 get the objective
    #CVXopt minimizes. but we want to maximize
    objFun = np.zeros((numVars,1))
    for deg, degval in dictLin.items():
        objFun[relaxationClass.deg2ind[deg]] += degval
    for deg, degval in dictPoly.items():
        objFun[relaxationClass.deg2ind[deg]] += degval
    objFun = -objFun

    #Solve
    nQuad = nx*(nx+1)//2
    NNN=0

    #Approximate solve
    #Scale the objective because otherwise its fails sometimes
    scaleFac = np.max(np.abs(objFun))
    objFun = objFun/scaleFac

    #Get the sparse representation
    AminCstr = sparse(matrix(AminCstr))
    AallCstr = sparse(matrix(AallCstr))
    BminCstr = matrix( BminCstr )
    BallCstr = matrix( BallCstr )
    while True:
        NNN+=1
        #TBD do we need to scale cstrs too??!?
        try:
            sol = solvers.sdp(matrix(objFun), Gl=AminCstr, hl=BminCstr, Gs=allCondA, hs=allCondB)
            assert sol['status'] == 'optimal'
        except:
            print("Minimal optimization failed")
            sol = solvers.sdp(matrix(objFun), Gl=AallCstr, hl=BallCstr, Gs=allCondA, hs=allCondB)
            if not(sol['status'] == 'optimal'):
                #Test if solution is valid anyways
                xSol = sol['x']
                assert np.all( np.array( AallCstr*xSol ) <= np.array(BallCstr)+1e-4 )#Allow for small violations
                Zm = toMatI( xSol, iMA )
                Zm[0,0]=1.
                e=np.linalg.eigvalsh(Zm)
                assert np.min(e) >= 1e-4
            break #No need to continue since all constraints are considered
        #Take current solution and check for violated constraints
        thisX = np.array(sol['x']).reshape((-1,1))
        #myCheckSol(thisX, [dictLin, dictPoly])
        #ARLTList, BRLTList = crtGeneralRLTPolyMinSortedAddLinCy(Axp=otherDict['linearCstr'][0], Bxp=otherDict['linearCstr'][1], Ax=relaxationClass.AtildeCstrBasex, Bx=relaxationClass.BtildeCstrBasex, AX=relaxationClass.AtildeCstrBaseX, BX=relaxationClass.BtildeCstrBaseX, Axz=relaxationClass.AtildeCstrBasexz, Bxz=relaxationClass.BtildeCstrBasexz)
        #AallCstr2 = np.vstack( [relaxationClass.AtildeCstrBase]+ARLTList )
        #BallCstr2 = np.vstack( [relaxationClass.BtildeCstrBase]+BRLTList )
        #The bound is only getting tighter by adding additional constraints
        #If the value is already negative -> exit
        print(sol['status'])
        if not(sol['status'] == 'optimal'):
            assert 0, "failed to optimize"
            print('CVX optimization failed')
        if -float(sol['primal objective'])*scaleFac < numericEps:
            break
        #addInd = np.where( (np.dot(AallCstr, thisX) - BallCstr) > - 1e-3 )[0]
        addInd = np.where(np.array(AallCstr*sol['x']-BallCstr) > -1e-5)[0]
        #Get rid of redundant ind
        addInd = addInd[~np.in1d(addInd,nrcor)]
        #addInd = list(map(int, np.where(np.array(AallCstr*sol['x']-BallCstr) > -1e-3)[0]))
        if 0:
            print(addInd)
            checkResult(thisX)

        if addInd.size == 0:
            break
        #nrcor = np.unique(np.hstack((nrcor, addInd)))
        nrcor = np.hstack((nrcor, addInd))
        #nrcor = np.hstack((nrmin, addInd)) #Already applied cstr should be satisfied
        #nrcor = addInd
        nrcorL = [int(i) for i in nrcor]
        AminCstr = AallCstr[nrcorL,:]
        BminCstr = BallCstr[nrcorL]

    #Test
    #solE,posE = exactSol(dictLin, dictPoly, **kwargs)
    #if -float(sol['primal objective'])*scaleFac < solE-1e-2:
    #    print('aaaaaaaaa')

    print('exit after ' + str(NNN)+ 'with '+'{0} of {1}'.format(AminCstr.size[0], AallCstr.size[0]))

    return -float(sol['primal objective'])*scaleFac, np.array(sol['x'])

###############################################################################
#Decide which calculation method to use
NCrelaxCalc=NCrelaxCalcIter
###############################################################################
#Exact solutions using couenne
#Test
def exactSol(dictLin, dictPoly, **kwargs):

    try:
        excludeInner = kwargs['excludeInner']
    except KeyError:
        excludeInner = None

    otherDict = {}
    otherDict.update(kwargs)

    cInst = couenneInst()
    #get variables
    for k in range(nx):
        cInst.addVar()
    #Add linear -> Planes
    cInst.addLinCstr( otherDict['linearCstr'][0][:,:nx], otherDict['linearCstr'][1] )
    #Add bounding box
    AbbC = np.vstack((  np.identity(nx), -np.identity(nx) ))
    BbbC = np.ones((2*nx,1))
    cInst.addLinCstr( AbbC, BbbC )
    #Unit sphere (for non-relaxed prob the bb is redundant)
    cInst.addQuadCstr(np.identity(nx), np.zeros((nx,1)), 1.0)
    #Exclude inner
    if not(excludeInner is None):
        cInst.addQuadCstr(-np.identity(nx), np.zeros((nx,1)), -excludeInner)

    allDict = {}
    for aKey in set(list(dictLin.keys()) + list(dictPoly.keys())):
        allDict[aKey] = 0.
    for aKey, aVal in dictLin.items():
        allDict[aKey] += aVal
    for aKey, aVal in dictPoly.items():
        allDict[aKey] += aVal
    cInst.addPolyObjasDict(allDict, seek='MAX')

    exactBoundPos, optimalSolPos, solTimePos = cInst.solve()
    print(exactBoundPos)
    print(optimalSolPos)

    return exactBoundPos[0], getPoly(np.array(optimalSolPos))[0]

######################################################
def getExactSolOfOrig(inPut):
    #exactSol optimizes in the transformed y space (the ellipsoid is transformed
    #into a hypersphere). This function operates in the original x space
    xDeg, zxDeg = dynSys.polyDegrees[:dynSys.polyNumbers[0]], dynSys.polyDegrees
    if len(inPut)== 13:
        thisT, Pt, Ct, Cti, dP, x0T, xd0T, perm, f, B, polyA, polyB, whichPart = inPut
        epsDeadZone = 0.
        innerAlpha = 0.
        excludeInner = None
    elif len(inPut)== 14:
        thisT, Pt, Ct, Cti, dP, x0T, xd0T, perm, f, B, polyA, polyB, whichPart, epsDeadZone = inPut
        innerAlpha = 0.
        excludeInner = None
    elif len(inPut)== 15:
        thisT, Pt, Ct, Cti, dP, x0T, xd0T, perm, f, B, polyA, polyB, whichPart, epsDeadZone,innerAlpha = inPut
        excludeInner = None
    else:
        thisT, Pt, Ct, Cti, dP, x0T, xd0T, perm, f, B, polyA, polyB, whichPart, epsDeadZone, innerAlpha, excludeInner = inPut

    thisDictDeg1 = {k:0. for k in lyapReg.degreeList1}
    thisDictDeg2 = {k:0. for k in lyapReg.degreeList2}

    epsDeadZone = 0. if epsDeadZone is None else epsDeadZone
    #get best input given the permutation
    ustar = dynSys.inputCstr.getThisU(perm, t=thisT)
    print(ustar)
    Bustar = ndot( B, ustar )

    #The total convergence expression in y is
    #Vd = 2*y'.P^1/2.(f(x_r)+Ax.z(P^-1/2.y)+Bustar-xd_r) + y'.P^-1/2'.dP.P^-1/2.y + \gamma*y'.y
    #Vd = 2.x'.P.(f(x_r)+Ax.z(x)+Bustar-xd_r) + x'.dP.x + \gamma*x'.P.x

    #get 2*y'.P^1/2.(f(x_r)+Bustar-xd_r)
    thisVals = 2.*ndot(Pt, (f+Bustar-xd0T))
    for k in range(nx):
        #thisDictDeg1[deg2str(yDeg[k])] += 2.*(f[k]+Bustar[k])
            thisDictDeg1[deg2str(xDeg[k])] += thisVals[k]

    #get the imposed minimal conv. rate \gamma*x'.P.x
    thisValP = Pt*lyapReg.convergenceRate
    for  k in range(nx):
        for l in range(nx):
            thisDictDeg2[deg2str(xDeg[k]+xDeg[l])] += thisValP[k,l]
    #get part of time-dependent shape
    #x'.dP.x
    for i in range(nx):
        for j in range(nx):
            thisDictDeg2[deg2str(xDeg[i]+xDeg[j])] += dP[i,j]
    #get the polynomial approx of dynamics
    #2*y'.P.A_xr.z(x)

    PA = 2.*ndot(Pt, polyA)
    uselessCounter=0
    doPolyB = not ( polyB is None)
    if doPolyB:
        for aB, aU in zip(polyB, ustar):
            PA += 2.*np.dot( Pt, aB*aU )
    for i in range(nx):
        #Loop over y
        for j, zxDeg in enumerate(dynSys.polyDegrees):
            #Loop over z
            thisDictDeg2[deg2str(xDeg[i]+zxDeg)] += PA[i,j]
            uselessCounter+=1

    #Do this more efficiently
    #B.resize((nx,nu))
    CB = ndot(Pt, B)
    CB = CB / np.tile(colWiseNorm(CB), (nx, 1))
    thisB = np.zeros((nu, numVars))
    for k in range(nu):
        if perm[k] == 1:
            thisB[k,:nx] =  CB[:,k] #Equivalent to B.T[k,:]
        else:
            thisB[k,:nx] = -CB[:,k]

    #Call couenne
    thisB = thisB[:,:nx]; alpha = -(0 if epsDeadZone is None else epsDeadZone)*np.ones((thisB.shape[0],1))
    cInst = couenneInst()
    #get variables
    for k in range(nx):
        cInst.addVar()
    #Add linear -> Planes
    cInst.addLinCstr( thisB, alpha )

    #Ellipsoid (for non-relaxed prob the bb is redundant)
    cInst.addQuadCstr(Pt, np.zeros((nx,1)), 1.0)
    #Exclude inner
    if not(excludeInner is None):
        cInst.addQuadCstr(-Pt, np.zeros((nx,1)), -excludeInner)
    allDict = {}
    for aKey in set(list(thisDictDeg1.keys()) + list(thisDictDeg2.keys())):
        allDict[aKey] = 0.
    for aKey, aVal in thisDictDeg1.items():
        allDict[aKey] += aVal
    for aKey, aVal in thisDictDeg2.items():
        allDict[aKey] += aVal
    cInst.addPolyObjasDict(allDict, seek='MAX')

    exactBoundPos, optimalSolPos, solTimePos = cInst.solve()

    return exactBoundPos[0], getPoly(np.array(optimalSolPos))[0]

######################################################
#Functions testing the convergence
#It takes the problem from its defintion in the original space x (ellipsoid)
#to the transformed space y (hypersphere)
def convPL(inPut, calcFun=NCrelaxCalc):
    #Get some shorthands
    yDeg, zyDeg = dynSys.polyDegrees[:dynSys.polyNumbers[0]], dynSys.polyDegrees

    thisDictDeg1 = {k:0. for k in lyapReg.degreeList1}
    thisDictDeg2 = {k:0. for k in lyapReg.degreeList2}

    thisPID = os.getpid()

    if len(inPut)== 13:
        thisT, Pt, Ct, Cti, dP, x0T, xd0T, perm, f, B, polyA, polyB, whichPart = inPut
        epsDeadZone = 0.
        innerAlpha = 0.
        excludeInner = None
    elif len(inPut)== 14:
        thisT, Pt, Ct, Cti, dP, x0T, xd0T, perm, f, B, polyA, polyB, whichPart, epsDeadZone = inPut
        innerAlpha = 0.
        excludeInner = None
    elif len(inPut)== 15:
        thisT, Pt, Ct, Cti, dP, x0T, xd0T, perm, f, B, polyA, polyB, whichPart, epsDeadZone,innerAlpha = inPut
        excludeInner = None
    else:
        thisT, Pt, Ct, Cti, dP, x0T, xd0T, perm, f, B, polyA, polyB, whichPart, epsDeadZone, innerAlpha, excludeInner = inPut

    epsDeadZone = 0. if epsDeadZone is None else epsDeadZone
    #get best input given the permutation
    ustar = dynSys.inputCstr.getThisU(perm, t=thisT)
    print(ustar)
    Bustar = ndot( B, ustar )

    #The total convergence expression in y is
    #Vd = 2*y'.P^1/2.(f(x_r)+Ax.z(P^-1/2.y)+Bustar-xd_r) + y'.P^-1/2'.dP.P^-1/2.y + \gamma*y'.y

    #get 2*y'.P^1/2.(f(x_r)+Bustar-xd_r)
    thisVals = 2.*ndot(Ct, (f+Bustar-xd0T))
    for k in range(nx):
        #thisDictDeg1[deg2str(yDeg[k])] += 2.*(f[k]+Bustar[k])
        thisDictDeg1[deg2str(yDeg[k])] += thisVals[k]

    #get the imposed minimal conv. rate \gamma*y'.y
    for  k in range(nx):
        thisDictDeg2[deg2str(yDeg[k]+yDeg[k])] += lyapReg.convergenceRate
    #get part of time-dependent shape
    #x'.dP.x=y'.P^-1/2'.dP.P^-1/2.y = y'.thisP.y
    thisP = ndot(Cti.T, dP, Cti)
    for i in range(nx):
        for j in range(nx):
            thisDictDeg2[deg2str(yDeg[i]+yDeg[j])] += thisP[i,j]
    #get the polynomial approx of dynamics
    #2*y'.P^1/2.A_xr.z(P^-1/2).y)
    #for i in range(nx):
    #    for j in range(self.dynSys.polyNumbers[-1]):
    #        thisDictDeg2[deg2str(yDeg[i]+zyDeg[j])] += 2.*polyA[i,j]
    #With self.transVarsCoefs and self.transVarsDegrees z(P^-1/2).y)[i] has the form
    #z(P^-1/2).y)[i] = \sum_j \prod(self.transVarsCoefs[i][j])*monomial_in_y(self.transVarsDegrees[i][j])

    #test
    #zYme = degsNCoefs2PolyVec(self.dynSys.xTrans, Cti, self.transVarsCoefs, self.transVarsDegrees)
    #zY = self.dynSys.getPolyVarsTrans(C=Ct)
    #test

    #This actually works because each monomial in x is expanded to the corresponding sum of monomials in y
    #monoX = prod_i x_f(i) <-> monoY =  prod_i Cti[f(i),:].y -> expand to sum of monos
    #TBD this should really be changed because it produces a lot of overhead
    #Idea: Use transformed dynmics with Ct as parameter in sympy and numpify
    PA = 2.*ndot(Ct, polyA)
    transCoefsNum = [ lmap( lambda thisInd: np.prod(Cti[thisInd].squeeze()), aMonomial ) for aMonomial in lyapReg.transVarsCoefs ]#This should be changed it is pretty slow
    uselessCounter=0
    doPolyB = not ( polyB is None)
    if doPolyB:
        for aB, aU in zip(polyB, ustar):
            PA += 2.*np.dot( Ct, aB*aU )
    for i in range(nx):
        #Loop over y
        for j in range(dynSys.polyNumbers[-1]):
            #Loop over z
            for zyDeg, zyCoef in  zip( lyapReg.transVarsDegrees[j], transCoefsNum[j] ):
                #Loop over u: polyB is given, get the non-linear effects of B(x).ustar
                thisDictDeg2[deg2str(yDeg[i]+zyDeg)] += PA[i,j]*zyCoef
                uselessCounter+=1

    #Do this more efficiently
    #B.resize((nx,nu))
    CB = ndot(Ct, B)
    CB = CB / np.tile(colWiseNorm(CB), (nx, 1))
    thisB = np.zeros((nu, numVars))
    for k in range(nu):
        if perm[k] == 1:
            thisB[k,:nx] =  CB[:,k] #Equivalent to B.T[k,:]
        else:
            thisB[k,:nx] = -CB[:,k]

    #If this turns out to be good it needs to be done more efficiently
    if lyapReg.polyInputSep and doPolyB:
        CB = ndot(Ct, B)
        #Do the partitioning based on relaxed polynomials
        thisBpoly = np.zeros((nu, numVars))
        for k, aB in enumerate(polyB):
            #Linear part
            thisBpoly[k,:nx] =  CB[:,k]
            PaB = ndot(Ct, aB)
            for i in range(nx):
                #Loop over y
                for j in range(dynSys.polyNumbers[-1]):
                    #Loop over z
                    for zyDeg, zyCoef in  zip( lyapReg.transVarsDegrees[j], transCoefsNum[j] ):
                        thisBpoly[k, relaxationClass.deg2ind[deg2str(yDeg[i]+zyDeg)] ] += PaB[i,j]*zyCoef
            #Check sign
            if not(perm[k] == 1):
                thisBpoly[k,:] *= -1
            #Normalize
            thisBpoly[k,:] /= np.linalg.norm(thisBpoly[k,:nx])
    else:
        thisBpoly = None

    #Get the cross-product of
    #crtGeneralRLTPolyMinSortedAll(Ax, Bx, AX=None, BX=None, Axz=None, Bxz=None)
    #The constraints here are all on y; So if thisB.y <= 0 is imposed.
    #if we set thisB.y <= \eps we can test different things depending on eps:
    #eps > 0 A non-checked zone is created around the separation hyperplanes, allowing for divergent behaviour here
    #eps < 0 The different zones overlap and we do not have to switch "infinitely fast when convergin to one of the hyperplanes
    #if relaxationClass.type == 'NCrelax':
    #    #thisConvBound = NCrelaxCalc(thisDictDeg1, thisDictDeg2, linearCstr=[thisB, np.zeros((nu,1))])
    #    if 0:
    #        thisConvBound = NCrelaxCalc(thisDictDeg1, thisDictDeg2, linearCstr=[thisB, -epsDeadZone*np.ones((nu,1))])
    #    else:
    #        #Use the "ideal" solution
    #        thisConvBound = NCrelaxCalc(thisDictDeg1, thisDictDeg2, linearCstr=[thisB, -epsDeadZone*np.ones((nu,1))], normalsSet=thisB[:,:nx], alpha = (max(epsDeadZone*np.sqrt(2), innerAlpha)+1.)/2., epsDeadZone=epsDeadZone )
    #else:
    #    assert 0, 'Not implemented'
    try:
        #Use the "ideal" solution
        #thisCalcFun = eval(calcFun)
        T=time.time()
        thisConvBound = calcFun(thisDictDeg1, thisDictDeg2, linearCstr=[thisB, -epsDeadZone*np.ones((nu,1))], normalsSet=thisB[:,:nx], alpha = (max(epsDeadZone*np.sqrt(2), 0 if innerAlpha is None else innerAlpha)+1.)/2., epsDeadZone=epsDeadZone, excludeInner=innerAlpha, polyCstr=[thisBpoly, -epsDeadZone*np.ones((nu,1))] )
        print(time.time()-T)
        if glbDBG:
            yy = thisConvBound[1][:nx].reshape((nx,1))
            myCheckSol(thisConvBound[1])
            xx = ndot(Cti, yy)
            print(ndot(xx.T, Pt, xx))

            fPoly = dynSys(x0T+xx, ustar, x0=x0T, mode='PP')
            fReal = dynSys(x0T+xx, ustar, mode='OO')
            dVP = 2.*ndot(xx.T,Pt,(fPoly-xd0T))+ndot(xx.T,dP,xx)
            dVR = 2.*ndot(xx.T,Pt,(fReal-xd0T))+ndot(xx.T,dP,xx)
            print("{0} : {1} : {2} : {3}".format(thisConvBound[0], dVP, thisConvBound[0]>=dVP-1.e-2, dVR))
            print("dist from plane is {0} for point x \n {1} \n y \n {2}".format( ndot(CB.T, yy), xx, yy ))
            for testK in range(0):
                thisDX = np.random.rand(nx,1)-0.5
                thisDX = thisDX/np.linalg.norm(thisDX)
                thisDX = ndot(Cti,thisDX*0.01)
                thisX = xx+thisDX
                if (ndot(thisX.T, Pt, thisX)>1. or np.any( ndot(thisB[:,:4], ndot(Ct, thisX)) > -epsDeadZone*np.ones((nu,1))-1e-4)):
                    continue
                fPolyPrime = dynSys(x0T+thisX, ustar, x0=x0T, mode='PP')
                dVPPrime = 2.*ndot(xx.T,Pt,(fPolyPrime-xd0T))+ndot(xx.T,dP,xx)
                print("{0} : {1}".format(dVP, dVPPrime))
                if dVPPrime>dVP-1e-2:
                    print('nooo')
    except:
        assert 0, "Call failed"

    #Test get optimal value for original prob
    #if 1:
        #solEOrig,posEOrig = getExactSolOfOrig(inPut)
        #print("Orig: {0}, Relax {1}".format(solEOrig, thisConvBound))

    return [float(thisConvBound[0]), whichPart]

######################################################

def convPLParallel(inQueue, outQueue, aFunc):
    #The parallelized version of convPL
    thisPID = os.getpid()
    while True:
        aInput = inQueue.get()
        if isinstance(aInput, str):
            outQueue.put([aInput, thisPID])
        else:
            outQueue.put( aFunc(aInput) )

    return 0

######################################################
def myCheckSol(xSolRelax, valDict=None):
    #The bound obtained by the linearization is strict if the matrix
    #|1, x.T, z.T|
    #|x,  X , Y  |
    #|z, Y.T, Z  |
    #is rank 1. The eigenvalues of
    #|1, x.T, z.T|   |1|
    #|x,  X , Y  | - |x|.|1, x.T, z.T|
    #|z, Y.T, Z  |   |z|
    #is a measure of the tightness
    #deltaZtilde, eigDeltaX, eigDeltaZ, eigDeltaZtilde = checkResult(xSolRelax)
    xSol, xSolM = getPoly(xSolRelax[:nx])

    xSolRelaxM = toMatInd(xSolRelax)
    print(np.linalg.eig(xSolRelaxM)[0])
    print(np.linalg.eig(xSolRelaxM[1:,1:]-xSolM[1:,1:])[0])

    if not (valDict is None):
        xR = xSolRelax[:nx].squeeze()
        resultRelax = 0.
        for aValDict in valDict:
            for aPower,aCoef in aValDict.items():
                resultRelax += aCoef*np.prod(np.power(xR,str2deg(aPower)))
    else:
        resultRelax=None

    return resultRelax


# pylint: disable=missing-function-docstring
# pylint: disable=invalid-name

from pyzwave.commandclass import NetworkManagementInclusion
from pyzwave.message import Message

def test_node_add_dsk_report():
    pkt = b"4\x13\x08\x00T\xcb\xc0}/_\x14\x1ee\x9e\x82\x82\xe67\xc5\x0e"
    msg: NetworkManagementInclusion.NodeAddDSKReport = Message.decode(pkt)
    assert isinstance(msg, NetworkManagementInclusion.NodeAddDSKReport)
    assert msg.seqNo == 8
    assert msg.inputDSKLength == 0
    assert msg.dsk == "21707-49277-12127-05150-26014-33410-58935-50446"

def test_node_add_status():
    pkt = b"\x34\x02\x0c\x06\x00N\x15\xd3\x9c\x04\x10\x01^%'\x85\\pru\x86ZYszh#\x00\x00\x00"
    msg = Message.decode(pkt)
    assert isinstance(msg, NetworkManagementInclusion.NodeAddStatus)
    assert msg.seqNo == 12
    assert msg.newNodeID == 78
    assert msg.commandClass == [
        94,
        37,
        39,
        133,
        92,
        112,
        114,
        117,
        134,
        90,
        89,
        115,
        122,
        104,
    ]

def test_node_add_status_partial():
    pkt = b"\x34\x02\x0c\x06\x00N\x15\xd3\x9c\x04\x10\x01^%'\x85\\pru\x86"
    msg = Message.decode(pkt)
    assert isinstance(msg, NetworkManagementInclusion.NodeAddStatus)
    assert msg.seqNo == 12
    assert msg.newNodeID == 78
    assert msg.commandClass == [
        94,
        37,
        39,
        133,
        92,
        112,
        114,
        117,
        134,
    ]


# -*- coding: utf-8 -*-
# __author__ = 'qingmei'
# modify 20180713

from biocluster.agent import Agent
from biocluster.tool import Tool
from biocluster.core.exceptions import OptionError

class GeneannoSortAgent(Agent):
    """
    anno.summary的排序
    """
    def __init__(self, parent):
        super(GeneannoSortAgent, self).__init__(parent)
        options = [
            {"name": "anno_summary", "type": "string"}
        ]
        self.add_option(options)
        self.step.add_steps('GeneannoSort')
        self.on('start', self.step_start)
        self.on('end', self.step_end)

    def step_start(self):
        self.step.GeneannoSort.start()
        self.step.update()

    def step_end(self):
        self.step.GeneannoSort.finish()
        self.step.update()

    def check_options(self):
        if not self.option("anno_summary"):
            raise OptionError("请设置anno_summary")    # 必须有

    def set_resource(self):
        """
        运行所需资源
        """
        self._cpu = 2
        self._memory = '3G'

    def end(self):
        super(GeneannoSortAgent, self).end()

class GeneannoSortTool(Tool):
    def __init__(self, config):
        super(GeneannoSortTool, self).__init__(config)
        self.sort_path = self.config.PACKAGE_DIR + "/wgs/sort_anno.summary.pl"
        self.perl_path = 'miniconda2/bin/perl'

    def geneannosort(self):
        """
        要重新写下！！！
        :return:
        """
        cmd = "{} {} -i {} -o {}"\
            .format(self.perl_path, self.sort_path, self.option("anno_summary"),
                    self.output_dir + "/anno.summary")
        self.logger.info(cmd)
        self.logger.info("开始进行GeneannoSort")
        command = self.add_command("geneannosort", cmd).run()  # nranno必须小写，
        self.wait(command)
        if command.return_code == 0:
            self.logger.info("GeneannoSort完成！")
        else:
            self.set_error("GeneannoSort出错！")

    def run(self):
        super(GeneannoSortTool, self).run()
        self.geneannosort()
        self.end()


from django import forms
from django.utils.translation import gettext as _
from django.template.loader import render_to_string
from django.contrib.admin.widgets import FilteredSelectMultiple
from bootstrap_modal_forms.forms import BSModalModelForm, BSModalForm
from constance import config

from utils.scraping import xml_parser, xml_sivin_parser
from utils.django.validators import validate_vin, vin_psa_isvalid
from utils.file.export import xml_corvet_file
from utils.conf import string_to_list
from psa.models import Corvet, Multimedia, Ecu
from .models import Xelon, Action, Sivin, ProductCode, ProductCategory
from .tasks import send_email_task
from utils.django.forms.fields import ListTextWidget
from utils.django.models import defaults_dict
from utils.file import LogFile
from utils.conf import CSD_ROOT

class IhmEmailModalForm(BSModalForm):
    to = forms.CharField(label='À', required=True, widget=forms.TextInput())
    cc = forms.CharField(label='Cc', widget=forms.TextInput())
    subject = forms.CharField(label='Objet', required=True, widget=forms.TextInput())
    message = forms.CharField(widget=forms.Textarea(attrs={'rows': 10}), required=True)

    def __init__(self, *args, **kwargs):
        super(IhmEmailModalForm, self).__init__(*args, **kwargs)
        cc_email_list = config.CSD_CC_EMAIL_LIST
        if self.request.user.email not in cc_email_list:
            cc_email_list = f"{self.request.user.email}; {cc_email_list}"
        self.fields['cc'].initial = cc_email_list

    def send_email(self):
        send_email_task.delay(
            subject=self.cleaned_data['subject'], body=self.cleaned_data['message'], from_email=self.request.user.email,
            to=string_to_list(self.cleaned_data['to']), cc=string_to_list(self.cleaned_data['cc'])
        )

    @staticmethod
    def vin_message(model, request):
        domain = config.WEBSITE_DOMAIN
        queryset = model.actions.filter(content__contains="OLD_VIN")
        rasp_log = LogFile(CSD_ROOT).vin_err_filter(model.modele_produit, model.numero_de_dossier)
        if queryset:
            data = queryset.first().content.split('\n')
            vins = {"old_vin": data[0][-17:], "new_vin": data[1][-17:]}
        else:
            vins = None
        message = render_to_string('squalaetp/email_format/vin_error_email.html', locals())
        return message

    @staticmethod
    def prod_message(model, request):
        domain = config.WEBSITE_DOMAIN
        queryset = model.actions.filter(content__contains="OLD_PROD")
        if queryset:
            data = queryset.first().content.split('\n')
            prods = {"old_prod": data[0][9:], "new_prod": data[1][9:]}
        else:
            prods = None
        message = render_to_string('squalaetp/email_format/prod_error_email.html', locals())
        return message

    @staticmethod
    def adm_message(model, request):
        domain = config.WEBSITE_DOMAIN
        if request.GET.get("select") == "prod":
            select = "modèle produit"
        else:
            select = "V.I.N."
        message = render_to_string('squalaetp/email_format/adm_email.html', locals())
        return message

class VinCorvetModalForm(BSModalModelForm):
    xml_data = forms.CharField(
        widget=forms.Textarea(
            attrs={
                'class': 'form-control',
                'placeholder': _("Data in XML format available on the RepairNAV site during CORVET extraction..."),
                'rows': 10,
            }
        ),
        required=False
    )

    class Meta:
        model = Xelon
        fields = ['vin']
        widgets = {
            'vin': forms.TextInput(
                attrs={'class': 'form-control', 'placeholder': _("Enter the VIN number"), 'autofocus': ''}
            ),
        }

    def __init__(self, *args, **kwargs):
        super(VinCorvetModalForm, self).__init__(*args, **kwargs)
        self.oldVin = self.instance.vin

    def clean_vin(self):
        data = self.cleaned_data['vin']
        message = validate_vin(data)
        if message:
            raise forms.ValidationError(_(message), code='invalid', params={'value': data})
        return data

    def clean_xml_data(self):
        xml_data = self.cleaned_data['xml_data']
        if xml_data:
            data = xml_parser(xml_data)
            no_fields = ['vin', 'btel', 'radio', 'bsi', 'emf', 'cmm', 'bsm']
            all_data = {key: '' for key in [f.name for f in Corvet._meta.local_fields if f.name not in no_fields]}
            all_data.update({'donnee_date_debut_garantie': None, 'donnee_date_entree_montage': None})
            vin = self.cleaned_data.get("vin")
            if isinstance(data, dict):
                all_data.update(data)
                if data.get('vin') == vin and data.get('donnee_date_entree_montage'):
                    if self.request.is_ajax():
                        xml_corvet_file(self.instance, xml_data, vin)
                if data.get('vin') != vin:
                    self.add_error('xml_data', _('XML data does not match VIN'))
            else:
                self.add_error('xml_data', _('Invalid XML data'))
                all_data = data
            return all_data
        return xml_data

    def clean(self):
        cleaned_data = super(VinCorvetModalForm, self).clean()
        vin = cleaned_data.get('vin')
        data = cleaned_data.get('xml_data')
        if vin and isinstance(data, dict) and not data.get('donnee_date_entree_montage'):
            raise forms.ValidationError(_('VIN error !'))
        elif vin != self.oldVin and vin_psa_isvalid(vin) and not isinstance(data, dict):
            if not Corvet.objects.filter(vin=vin):
                raise forms.ValidationError(_('New PSA VIN, please use the Import CORVET button !'))

    def save(self, commit=True):
        instance = super().save(commit=False)
        if commit and not self.request.is_ajax():
            data = self.cleaned_data['xml_data']
            vin = self.cleaned_data['vin']
            if data and vin:
                defaults = defaults_dict(Corvet, data, 'vin')
                Corvet.objects.update_or_create(vin=vin, defaults=defaults)
            if vin != self.oldVin:
                content = "OLD_VIN: {}\nNEW_VIN: {}".format(self.oldVin, vin)
                Action.objects.create(content=content, content_object=self.instance)
            instance.save()
        return instance

class ProductModalForm(BSModalModelForm):
    class Meta:
        model = Xelon
        fields = ['modele_produit', 'modele_vehicule']
        widgets = {'modele_vehicule': forms.TextInput(attrs={'readonly': True})}

    def __init__(self, *args, **kwargs):
        products = ProductCategory.objects.exclude(product_model="").order_by('product_model')
        self.data_list = list(products.values_list('product_model', flat=True).distinct())
        super(ProductModalForm, self).__init__(*args, **kwargs)
        self.fields['modele_produit'].widget = ListTextWidget(data_list=self.data_list, name='value-list')
        self.fields['modele_produit'].required = True
        self.oldProduct = self.instance.modele_produit
        self.oldVehicle = self.instance.modele_vehicule

    def clean_modele_produit(self):
        data = self.cleaned_data['modele_produit']
        if data not in self.data_list:
            self.add_error('modele_produit', _('Xelon product model does not exist !'))
        return data

    def save(self, commit=True):
        instance = super().save(commit=False)
        if commit and not self.request.is_ajax():
            product = self.cleaned_data['modele_produit']
            vehicle = self.cleaned_data['modele_vehicule']
            if product and vehicle and not self.request.is_ajax():
                if product != self.oldProduct:
                    content = "OLD_PROD: {}\nNEW_PROD: {}".format(self.oldProduct, product)
                    Action.objects.create(content=content, content_object=self.instance)
                if vehicle != self.oldVehicle:
                    content = "OLD_VEH: {}\nNEW_VEH: {}".format(self.oldProduct, vehicle)
                    Action.objects.create(content=content, content_object=self.instance)
            instance.save()
        return instance

class SivinModalForm(BSModalModelForm):
    immat_siv = forms.CharField(
        widget=forms.TextInput(
            attrs={'class': 'form-control', 'placeholder': _("Enter the IMMAT number"), 'autofocus': ''}
        )
    )
    xml_data = forms.CharField(
        widget=forms.Textarea(
            attrs={
                'class': 'form-control',
                'placeholder': _("Data in XML format available on the RepairNAV site during SIVIN extraction..."),
                'rows': 10,
            }
        ),
        required=True
    )

    class Meta:
        model = Sivin
        exclude = ["corvet"]

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['codif_vin'].required = False

    def clean_xml_data(self):
        xml_data = self.cleaned_data['xml_data']
        immat_siv = self.cleaned_data.get('immat_siv', '').upper()
        data = xml_sivin_parser(xml_data)
        if isinstance(data, dict):
            if data.get('immat_siv') == immat_siv:
                for field, value in data.items():
                    self.cleaned_data[field] = value
                return xml_data
            self.add_error('xml_data', _('XML data does not match IMMAT'))
        else:
            self.add_error('xml_data', _('Invalid XML data'))
        return xml_data

    def save(self, commit=True):
        del self.fields['xml_data']
        instance = super().save(commit=False)
        if commit and not self.request.is_ajax():
            instance.save()
        return instance

class ProductCodeAdminForm(forms.ModelForm):
    medias = forms.ModelMultipleChoiceField(
        queryset=Multimedia.objects.all(), widget=FilteredSelectMultiple("Multimedia", is_stacked=False),
        required=False)
    ecus = forms.ModelMultipleChoiceField(
        queryset=Ecu.objects.all(), widget=FilteredSelectMultiple("Ecu", is_stacked=False), required=False)

    class Meta:
        model = ProductCode
        fields = ['name', 'medias', 'ecus']

class XelonCloseModalForm(BSModalModelForm):

    class Meta:
        model = Xelon
        fields = ['type_de_cloture']

    def save(self, commit=True):
        instance = super().save(commit=False)
        if commit and not self.request.is_ajax():
            instance.type_de_cloture = "N/A"
            instance.save()
            Action.objects.create(content="Dossier en retard => FAIT", content_object=instance)
        return instance


# -*- coding: utf-8 -*-

from mdstudio_structures.cheminfo_molhandle import mol_read, mol_validate_file_object

class CheminfoDescriptorsWampApi(object):
    """
    Cheminformatics descriptors WAMP API
    """

    @staticmethod
    def get_descriptors(request, claims):

        # Import the molecule
        mol = mol_validate_file_object(request['mol'])
        molobject = mol_read(mol['content'], mol_format=mol['extension'], toolkit=request["toolkit"])
        desc = molobject.calcdesc()

        if desc is not None:
            status = 'completed'
            output = desc
        else:
            status = 'failed'
            output = None

        return {'session': status, 'descriptors': output}


"""
You have been watching a video for some time. Knowing the total video duration find out what portion of the video you have
already watched.

Example

For part = "02:20:00" and total = "07:00:00", the output should be
  videoPart(part, total) = [1, 3].

You have watched 1 / 3 of the whole video.
"""

from fractions import Fraction as frac

def videoPart(part, total):
  part = part.split(":")
  total = total.split(":")

  p_seconds = int(part[0]) * 3600 + int(part[1]) * 60 + int(part[2])

  t_seconds = int(total[0]) * 3600 + int(total[1]) * 60 + int(total[2])

  j = frac(p_seconds, t_seconds)

  return (j.numerator, j.denominator)


import cv2
import numpy as np
from matplotlib import pyplot as plt

imageSource = "5_histogram.jpeg"
image = cv2.imread(imageSource)
outputFigure = "image_03_03.png"
n = 2
m = 2
kernelSize = np.array([[0, -1, 0], [-1, 5, -1], [0, -1, 0]])

sharp = cv2.filter2D(src=image, ddepth=-1, kernel=kernelSize)
sharpOther = cv2.GaussianBlur(src=image, ksize=(9, 9), sigmaX=10)
sharpOther = cv2.addWeighted(src1=image, alpha=1.5, src2=sharpOther, beta=-0.5, gamma=0)
cv2.imshow("Exercise 2: blur version 1", np.hstack((image, sharp)))
cv2.imshow("Exercise 2: blur version 2", np.hstack((image, sharpOther)))
cv2.imwrite("image_03_01.png", np.hstack((image, sharp)))
cv2.imwrite("image_03_02.png", np.hstack((image, sharpOther)))
cv2.waitKey(0)
cv2.destroyAllWindows()

figure, axs = plt.subplots(n, m)
figure.set_size_inches(10, 7)
figure.suptitle("Exercise 3: Sharp image")
plt.tight_layout(h_pad=1)
axs[0][0].imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
axs[0][0].set_title("original: ")
axs[0][1].imshow(cv2.cvtColor(sharp, cv2.COLOR_BGR2RGB))
axs[0][1].set_title("sharp v1: filter2D")
axs[1][0].imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
axs[1][0].set_title("original: ")
axs[1][1].imshow(cv2.cvtColor(sharpOther, cv2.COLOR_BGR2RGB))
axs[1][1].set_title("sharp v2: gaussian + addWeigh")
plt.savefig(outputFigure)
plt.show()


# Standard
# None

# Pip
import typer

# Custom
# None

class MessageKeys:
    """
    This class contains the strings for the respective functions
    so that they can be accessed through dot notation.
    """

    class GenerateDir:
        """
        see function generate_directories
        """

        generate_dir = "gen-dir"
        generate_dir_help = "Generate directories where the files should reside."

        generating_dir = "Directories being generated."
        directory_generated = typer.style(
            "Directories have been generated.", fg=typer.colors.GREEN
        )
        folders_exists = typer.style(
            "The folders already exist in this directory.", fg=typer.colors.RED
        )

    class GeneratePdf:
        """
        see function generate_pdf
        """

        generate_pdf_name = "gen-pdf"
        generate_pdf_command = "Generate a .pdf from a collection of images."
        images_generate = typer.style(
            "The .pdf file is being generated. Please wait...",
            fg=typer.colors.BRIGHT_MAGENTA,
        )
        generate_pdf_help = "Enter the save name of the .pdf file"
        file_created = typer.style(
            ".pdf file was successfully created!", fg=typer.colors.GREEN
        )
        no_images = typer.style(
            "Error: Please make sure that there are images in the image directory ",
            fg=typer.colors.RED,
        )

        images_removed = typer.style(
            "The images have been removed from the directory",
            fg=typer.colors.RED,
        )

        retain_images = typer.style("Images will not be deleted",
                                    fg=typer.colors.GREEN)

        missing_directory = typer.style(
            "Error: The image directory is missing!", fg=typer.colors.RED
        )

        generate_custom_dir_long = "--dir"
        generate_custom_dir_short = "-d"
        generate_custom_dir_help = ""

        generated_file_name_long = "--save"
        generated_file_name_short = "-s"

    class AddMetadata:
        """
        see function add_metadata
        """

        add_metadata_name = "add-metadata"
        add_metadata_help = (
            "Add the data from the .yaml file " "to the .pdf as metadata."
        )

        meta_pdf = "The name of the .pdf that should have metadata added."
        save_name = "The name of the new .pdf file with metadata."
        yaml_error = typer.style(
            "The .yaml file could not be parsed. "
            "\nPlease make sure that you have "
            "correctly formatted the .yaml file",
            fg=typer.colors.RED,
        )

        yaml_not_exist = typer.style(
            "The .yaml file that you have selected does not exist.",
            fg=typer.colors.RED
        )

        pdf_not_exists = typer.style(
            "The .pdf either does not exist or the "
            "file name was not entered correctly. "
            "Please check the file name.",
            fg=typer.colors.RED,
        )

        pdf_corrupt = typer.style(
            "The file you entered is either corrput or "
            "is not a .pdf file. "
            "Please check the file again.",
            fg=typer.colors.RED,
        )

        yaml_config = "The name of the .yaml file which contains the config data."
        metadata_added = typer.style(
            "The metadata has been successfully added!", fg=typer.colors.GREEN
        )

        results = "results"


from urllib.request import Request, urlopen
import json

def fetch_item_images(dictionary, json_url, path_url):
    item_image_links = {}
    request = Request(json_url, headers={"User-Agent": "Mozilla/5.0"})
    response = urlopen(request).read()
    data_json = json.loads(response)
    for unit in dictionary:
        for value in dictionary[unit]:
            for element in data_json:
                for items in data_json[element]:
                    for properties in items:
                        if properties == "apiName" and items[properties] == value:
                            path = items["icon"].lower()
                            end = path.find(".dds")
                            path = path[:end] + ".png"
                            if unit not in item_image_links:
                                item_image_links[unit] = [{value: path_url + path}]
                            else:
                                item_image_links[unit] += [{value: path_url + path}]
    return item_image_links


'''
Date: 11/20/2020 19:49:08
LastEditTime: 11/20/2020 19:49:44
Description: LCA
'''

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        if not root:
            return None
        while root:
            if root.val > p.val and root.val > q.val:
                root = root.left
            elif root.val < p.val and root.val < q.val:
                root = root.right
            else:
                return root
        return None


import random

def randomArray(arrayLength):
  array = []
  for i in range(arrayLength):
    array.append(random.randint(0,100))
  return array

def findByBinarySearch(array, number):
  print("Finding number {} in {}".format(number, array))
  array.sort()
  print("Sorted array {}".format(array))
  tries = 0
  low = 0
  high = len(array) - 1
  while True:
    tries += 1
    mid = int((high + low) / 2)
    if (array[mid] == number):
      index = array.index(number)
      print("Number found in index {} in {} tries".format(index,tries))
      break
    elif (array[mid] > number):
      high = mid - 1
    else:
      low = mid + 1

def run():
  arrayLenght = random.randint(1,20)
  array = randomArray(arrayLenght)
  numberToFind = array[random.randint(0, arrayLenght - 1)]
  findByBinarySearch(array,numberToFind)

if __name__ == "__main__":
  run()


from database import db
from sqlalchemy import exc, text
from random import choice
from string import digits
from cv2 import imread, warpAffine, resize, INTER_AREA, imwrite
import numpy as np

# from re import match

def discard_num(val: str):
    try:
        int(val)
        return False
    except ValueError as e:
        return True

def username_generator(name: str):
    try:
        with db.connect() as conn:
            user_names = conn.execute(
                text(f"""SELECT user_name FROM user_info""")
            ).all()
            name_split = [word for item in name.split() for word in item.split("_")]
            name_split = list(filter(discard_num, name_split))
            if len(name_split[0]) >= 16:
                name = name_split[0][:16]
            elif len(name_split[0]) <= 8 and len(name_split[1]) <= 8:
                name = name_split[1] + name_split[0]
            else:
                name = name_split[0]
            while True:
                temp = name + "".join([choice(digits) for _ in range(4)])
                if not any([True if item[0] == temp else False for item in user_names]):
                    name = temp
                    break

            return name

            # print(match(r"^[\w\.]{6,20}$", name))
            # print(any([True if item[0] == name else False for item in user_names]))

    except (Exception, exc.SQLAlchemyError) as e:
        print(e)

def get_file_size(file: object):
    try:
        if file:
            # method to read size of incoming file over the internet
            size_of_file = 0
            data = file.stream.read(1024)

            while data:
                size_of_file += len(data)
                file.stream.flush()
                data = file.stream.read(1024)

            file.stream.seek(0)
            return {"size": size_of_file}

    except (Exception, IOError) as e:
        print(e)
        return {"size": 0}

def edit_profile_picture(
    image: str, width: int, height: int, translateX: int, translateY: int
):
    try:
        width = int(width) + 8
        height = int(height) + 8
        translateX = float(translateX)
        translateY = float(translateY)

        print(width, height, translateX, translateY)

        init_img = imread(image)
        resize_img = resize(init_img, (width, height), INTER_AREA)

        t_matrix = np.float32(
            [
                [1, 0, translateX],
                [0, 1, translateY],
            ]
        )

        translate_img = warpAffine(resize_img, t_matrix, (width, height))

        crop_img = translate_img[0:300, 0:300]

        imwrite(image, crop_img)

        return True

    except Exception as e:
        print(e)
        return False


#!/usr/bin/env python3

raw = open("input.txt").read().strip()

full = len(raw)
half = len(raw) // 2

answer1 = 0
answer2 = 0

for i in range(full):
	if raw[i] == raw[(i+1) % full]:
		answer1 += int(raw[i])

	if raw[i] == raw[(i+(half)) % full]:
		answer2 += int(raw[i])

print(answer1)
print(answer2)


from datetime import timedelta
from flask import current_app, request, g, redirect, url_for
from flask.views import MethodView
from flask_smorest import abort
from swpt_creditors.schemas import (
    examples,
    CreditorSchema,
    WalletSchema,
    LogEntriesPageSchema,
    LogPaginationParamsSchema,
    AccountsListSchema,
    TransfersListSchema,
    PinInfoSchema,
)
from swpt_creditors import procedures
from .common import context, ensure_creditor_permissions, Blueprint
from .specs import CID
from . import specs

creditors_api = Blueprint(
    "creditors",
    __name__,
    url_prefix="/creditors",
    description="""**Obtain information about existing creditors, change
    creditors' PINs.** There are two important concepts here: Each creditor
    has a *"wallet"*, which contains references to various kinds of
    information about the creditor (like creditor's list of accounts
    and transfers). The other important concept is the creditor's
    *"log"*. Whenever there is new information that the creditor
    should be aware of, a record will be added to the creditor's log,
    referring to the created/updated/deleted object. The purpose of
    the log is to allow the clients of the API to reliably synchronize
    their local databases with the server, simply by following the
    "log".""",
)
creditors_api.before_request(ensure_creditor_permissions)

@creditors_api.route("/.wallet")
class RedirectToWalletEndpoint(MethodView):
    @creditors_api.response(204)
    @creditors_api.doc(
        operationId="redirectToWallet",
        security=specs.SCOPE_ACCESS_READONLY,
        responses={204: specs.WALLET_DOES_NOT_EXIST, 303: specs.WALLET_EXISTS},
    )
    def get(self):
        """Redirect to the creditor's wallet."""

        creditorId = g.creditor_id
        if creditorId is not None:
            location = url_for(
                "creditors.WalletEndpoint",
                _external=True,
                creditorId=creditorId,
            )
            return redirect(location, code=303)

@creditors_api.route("/<i64:creditorId>/", parameters=[CID])
class CreditorEndpoint(MethodView):
    @creditors_api.response(200, CreditorSchema(context=context))
    @creditors_api.doc(
        operationId="getCreditor", security=specs.SCOPE_ACCESS_READONLY
    )
    def get(self, creditorId):
        """Return a creditor."""

        return procedures.get_active_creditor(creditorId) or abort(403)

@creditors_api.route("/<i64:creditorId>/wallet", parameters=[CID])
class WalletEndpoint(MethodView):
    @creditors_api.response(200, WalletSchema(context=context))
    @creditors_api.doc(
        operationId="getWallet", security=specs.SCOPE_ACCESS_READONLY
    )
    def get(self, creditorId):
        """Return creditor's wallet.

        The creditor's wallet "contains" all creditor's accounts,
        pending transfers, and recent events (the log). In short: it
        is the gateway to all objects and operations in the API.

        """

        return procedures.get_active_creditor(
            creditorId, join_pin=True
        ) or abort(404)

@creditors_api.route("/<i64:creditorId>/pin", parameters=[CID])
class PinInfoEndpoint(MethodView):
    @creditors_api.response(200, PinInfoSchema(context=context))
    @creditors_api.doc(
        operationId="getPinInfo", security=specs.SCOPE_ACCESS_READONLY
    )
    def get(self, creditorId):
        """Return creditor's PIN information."""

        return procedures.get_pin_info(creditorId) or abort(404)

    @creditors_api.arguments(PinInfoSchema)
    @creditors_api.response(200, PinInfoSchema(context=context))
    @creditors_api.doc(
        operationId="updatePinInfo",
        security=specs.SCOPE_ACCESS_MODIFY,
        responses={403: specs.FORBIDDEN_OPERATION, 409: specs.UPDATE_CONFLICT},
    )
    def patch(self, pin_info, creditorId):
        """Update creditor's PIN information.

        **Note:** This is a potentially dangerous operation which may
        require a PIN. Also, normally this is an idempotent operation,
        but when an incorrect PIN is supplied, repeating the operation
        may result in the creditor's PIN being blocked.

        """

        try:
            return procedures.update_pin_info(
                creditor_id=creditorId,
                status_name=pin_info["status_name"],
                secret=current_app.config["PIN_PROTECTION_SECRET"],
                new_pin_value=pin_info.get("optional_new_pin_value"),
                latest_update_id=pin_info["latest_update_id"],
                pin_reset_mode=g.pin_reset_mode,
                pin_value=pin_info.get("optional_pin"),
                pin_failures_reset_interval=timedelta(
                    days=current_app.config["APP_PIN_FAILURES_RESET_DAYS"]
                ),
            )
        except procedures.WrongPinValue:
            abort(403)
        except procedures.CreditorDoesNotExist:
            abort(404)
        except procedures.UpdateConflict:
            abort(
                409, errors={"json": {"latestUpdateId": ["Incorrect value."]}}
            )

@creditors_api.route("/<i64:creditorId>/log", parameters=[CID])
class LogEntriesEndpoint(MethodView):
    @creditors_api.arguments(LogPaginationParamsSchema, location="query")
    @creditors_api.response(
        200,
        LogEntriesPageSchema(context=context),
        example=examples.LOG_ENTRIES_EXAMPLE,
    )
    @creditors_api.doc(
        operationId="getLogPage", security=specs.SCOPE_ACCESS_READONLY
    )
    def get(self, params, creditorId):
        """Return a collection of creditor's recent log entries.

        The returned object will be a fragment (a page) of a paginated
        list. The paginated list contains recent log entries. The
        returned fragment, and all the subsequent fragments, will be
        sorted in chronological order (smaller `entryId`s go
        first).

        **Note:** The number of items in the returned fragment should
        be small enough, so that all the items in the fragment can be
        processed and saved to the client's local database in a single
        database transaction.

        """

        n = current_app.config["APP_LOG_ENTRIES_PER_PAGE"]
        try:
            log_entries, last_log_entry_id = procedures.get_log_entries(
                creditorId,
                count=n,
                prev=params["prev"],
            )
        except procedures.CreditorDoesNotExist:
            abort(404)

        if len(log_entries) < n:
            # The last page does not have a 'next' link.
            return {
                "uri": request.full_path,
                "items": log_entries,
                "forthcoming": f"?prev={last_log_entry_id}",
            }

        return {
            "uri": request.full_path,
            "items": log_entries,
            "next": f"?prev={log_entries[-1].entry_id}",
        }

@creditors_api.route("/<i64:creditorId>/accounts-list", parameters=[CID])
class AccountsListEndpoint(MethodView):
    @creditors_api.response(
        200,
        AccountsListSchema(context=context),
        example=examples.ACCOUNTS_LIST_EXAMPLE,
    )
    @creditors_api.doc(
        operationId="getAccountsList", security=specs.SCOPE_ACCESS_READONLY
    )
    def get(self, creditorId):
        """Return a paginated list of links to all accounts belonging to a
        creditor.

        The paginated list will not be sorted in any particular order.

        """

        return procedures.get_active_creditor(creditorId) or abort(404)

@creditors_api.route("/<i64:creditorId>/transfers-list", parameters=[CID])
class TransfersListEndpoint(MethodView):
    @creditors_api.response(
        200,
        TransfersListSchema(context=context),
        example=examples.TRANSFERS_LIST_EXAMPLE,
    )
    @creditors_api.doc(
        operationId="getTransfersList", security=specs.SCOPE_ACCESS_READONLY
    )
    def get(self, creditorId):
        """Return a paginated list of links to all transfers belonging to a
        creditor.

        The paginated list will not be sorted in any particular order.

        """

        return procedures.get_active_creditor(creditorId) or abort(404)


import numpy as np

class Gyroscope:
	def __init__(self, sigma_x, sigma_y, sigma_z, e_delta_x, e_delta_y, e_delta_z, bits = 16, range = 250):
		self.sigma = np.array([[sigma_x, 0, 0],[0, sigma_y, 0],[0, 0, sigma_z]])
		self.delta = np.array([0,0,0])
		self.e_delta = np.array([[e_delta_x, 0, 0],[0, e_delta_y, 0],[0, 0, e_delta_z]])

	def get_rotation(self, omega):
		e = np.random.multivariate_normal([0,0,0], self.sigma)
		self.delta = self.delta + np.random.multivariate_normal([0,0,0], self.e_delta)
		y = omega + e
		return np.float16(y)

if __name__ == "__main__":
	g = Gyroscope(1,1,1,1,1,1)

	f, (ax1, ax2, ax3) = plt.subplots(3,1)
	for i in range(0, 10):
		omega = g.get_rotation(np.array([0,0,0]))
		print(omega)


dog = {'owner': 'columbo',
       'type': 'dog',
       'name': 'dog',
       }
fifi = {'owner' : 'someone',
        'type': 'dog',
        'name': 'fifi'
        }
bobbi = {'owner' : 'a different person',
         'type': 'bird',
         'name': 'bobbi',
         }
sherm = {'owner' : 'that person',
         'type' : 'cat',
         'name': 'sherm',
         }
little_devil = {'owner' : 'dad',
                'type' : 'cat',
                'name' : 'little devil',
                }
silage = {'owner' : 'me',
          'type' : 'cow',
          'name': 'silage',
          }
apple = {'owner' : 'me',
         'type' : 'rabbit',
         'name': 'apple',
         }
pets = [dog,fifi, sherm, little_devil, silage, apple]

for pet in pets:
    for trait, fact in pet.items():
        print('\t' +trait +': '+fact)
    print('\n')


#!/usr/bin/env python
# -*- coding:utf-8 -*-
n = int(input())
l = input()
bad = set()
hasprinted = set()

count = 1
pre = l[0]
for i in l[1:]:
    if i == pre:
        count += 1
    else:
        if count % n == 0:
            bad.add(pre)
        else:
            bad.discard(pre)
        count = 1
        pre = i

if count % n == 0:
    bad.add(pre)
else:
    bad.discard(pre)

i = 0
fs = "\n"
while i < len(l):
    fs += l[i]
    if l[i] in bad:
        if l[i:i+n] != l[i]*n:
            bad.discard(l[i])
            i += 1
        else:
            if(l[i] not in hasprinted):
                print(l[i], end="")
                hasprinted.add(l[i])
            i += n
    else:
        i += 1

print(fs)


from django.shortcuts import render, redirect

from onlineLibrary.books_app.models import Book
from onlineLibrary.user_app.forms import UserForm, DeleteUser
from onlineLibrary.user_app.models import Profile

def show_home(request):
    user = Profile.objects.first()
    if not user:
        form = UserForm()
        context = {
            'form': form
        }
        return render(request, 'home-no-profile.html', context)
    books = Book.objects.all()
    context = {
        'user': user,
        'books': books,
    }
    return render(request, 'home-with-profile.html', context)

def create_profile(request):
    if request.method == 'POST':
        form = UserForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('home')
    form = UserForm()
    context = {
        'form': form,
    }
    return render(request, 'home-no-profile.html', context)

def show_profile(request):
    user = Profile.objects.first()
    context = {
        'user': user,
    }
    return render(request, 'profile.html', context)

def edit_profile(request):
    user = Profile.objects.first()
    if request.method == 'POST':
        form = UserForm(request.POST, instance=user)
        if form.is_valid():
            form.save()
            return redirect('home')
        context = {
            'form': form,
            'user': user,
        }
        return render(request, 'edit-profile.html', context)
    form = UserForm(instance=user)
    context = {
        'form': form,
        'user': user,
    }
    return render(request, 'edit-profile.html', context)

def delete_profile(request):
    user = Profile.objects.first()
    books = Book.objects.all()
    if request.method == 'POST':
        Profile.objects.all().delete()
        books.delete()
        return redirect('home')

    if request.method == 'GET':
        form = DeleteUser(instance=user)
        context = {
            'user': user,
            'form': form,
        }
        return render(request, 'delete-profile.html', context)


import random, os, pickle

players = {}

#check to see if there is an existing file, if there is ask the user if they want to open it
if(os.path.exists('playersdict')):
    openfile = input("Do you want to open the existing players file? (y/n) [y] ")
    if(openfile != 'n'):
        filetoload = open("playersdict","rb")
        players = pickle.load(filetoload)
        filetoload.close()
#print a list of names
def printplayers():
    print("Current players are: ")
    for player in players.keys():
        print(player)

printplayers()

def diceroll(numberofsides):
    return random.randint(1,int(numberofsides))

#get the int to add to the attribute
def getbittoadd():
    dicea = diceroll(12)
    diceb = diceroll(4)
    return round(dicea/diceb)

#create a player
def createplayer(name):
    strength = 10
    skill = 10
    skill += getbittoadd()
    strength += getbittoadd()
    player = {'name':name, 'skill':skill, 'strength':strength}
    return player

#add players to the dictionary
while(input("Add another player? (y/n) [n] ") == 'y'):
    name = input("Enter the player's name: ")
    players[name] = createplayer(name)
    printplayers()

printplayers()
print(players)

#pickle the dictionary
filetosave = open('playersdict','wb')
pickle.dump(players,filetosave)
filetosave.close()


from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import UserViewSet, UserProfileInterestsViewSet, User_Type_ViewSet, UserLoginCountViewSet

router = DefaultRouter()
router.register('users', UserViewSet, basename='users')
router.register('userinterests', UserProfileInterestsViewSet, basename='userinterests')
router.register('usertypes', User_Type_ViewSet, basename='usertypes')
router.register("user_login_counts", UserLoginCountViewSet, basename="user_login_counts")

urlpatterns = [
    path('api/', include(router.urls)),

]