def inverse_1_2_exact(small_matrix, dtype=f64):
    """Performs inverse of small matrices of size 1 or 2 by simple formulas

    Args:
        small_matrix (np.array): matrix for inverse searching

    Returns:
        np.array: inverse of small matrix

    Raises:
        Exception: An error occurred because matrix is not 1x1 or 2x2
        Exception: An error occurred because matrix of size 1x1 or 2x2 is singular
    """
    with bf.Context(precision=EXACT_PRECISION):
        if small_matrix.shape == (1, 1):
            if small_matrix[0, 0] == 0:
                raise Exception('Matrix of size 1x1 is singular')
            return np.array([[1.0 / small_matrix[0, 0]]], dtype=dtype)
        if small_matrix.shape != (2, 2):
            raise Exception("Matrix isn't 2x2 matrix")
        a = small_matrix[0, 0]
        b = small_matrix[0, 1]
        c = small_matrix[1, 0]
        d = small_matrix[1, 1]
        det = bf.sub(bf.mul(a, d), bf.mul(b, c))
        #det = a * d - b * c
        if det == 0:
            raise Exception('Matrix of size 2x2 is singular')
        inverse = np.zeros(small_matrix.shape, dtype=dtype)
        inverse[0, 0] = bf.div(d,  det)
        inverse[0, 1] = bf.div(-c,  det)
        inverse[1, 0] = bf.div(-b,  det)
        inverse[1, 1] = bf.div(a,  det)
        return inverse
Пример #2
0
def Evaluate(pk,cl,ck,s={}):
    #S is for debugging
    (pk0,x,y)=pk
    cl0=[]
    for (i,j) in cl:
        cl0.append(i)
    c0 = SomeWhatEvaluate((pk0,x), cl0, ck)
    z=[None]*(Params.bigo+1)
    for i in range(1,Params.bigo+1):
        k=bigfloat.mul(c0,y[i],bigfloat.precision((Params.kappa+Params.gamma)))
        z[i]=float(bigfloat.mod(k,2,bigfloat.precision((Params.prec))))
    if debug:
        su=0
        yo=0
        for i in range(1,Params.bigo+1):
            if s[i]==1:
                yo=bigfloat.add(yo,y[i],bigfloat.precision((Params.kappa+Params.gamma)))
                su=bigfloat.add(su,z[i],bigfloat.precision(Params.kappa+Params.gamma))
        print "Enc_sum%2=",bigfloat.mod(su,8,bigfloat.precision((Params.prec+Params.gamma)))
        q=bigfloat.div(c0,globsk,bigfloat.precision(Params.kappa+Params.gamma))
        print "(c0/sk)=",q
        q=bigfloat.mul(c0,yo,bigfloat.precision((Params.kappa+Params.gamma)))
        print "(c0*yo)=",q
        q=bigfloat.div(1,globsk,bigfloat.precision(Params.kappa+Params.gamma))
        print "(1/sk)=",q
        print "(yo)=",yo
        print "(c0*1/sk)=",bigfloat.mul(q,c0,bigfloat.precision((Params.prec+Params.gamma)))
        q=bigfloat.div(c0,globsk,bigfloat.precision((Params.prec+Params.gamma)))
        print "(c0/sk)=",q
    c = (c0,z)
    return c
Пример #3
0
 def _compute_grad(self, children: List) -> bf.BigFloat:
     context = bf.precision(self.grad_precision) + bf.RoundAwayFromZero
     grad = 0
     for (w1, w2), var in children:
         lower, upper = var.grad()
         grad_term = bf.add(bf.mul(w1, lower, context), bf.mul(w2, upper, context), context)
         grad = bf.add(grad_term, grad, context)
     return grad
def partial_right_two_exact(matrix, v1, v2, i1, i2):
    with bf.Context(precision=EXACT_PRECISION):
        n = matrix.shape[0]
        mul1 = matrix[:, i1]
        mul2 = matrix[:, i2]
        low_bound = 2
        for j in xrange(low_bound, n, 1):
            v1_j = bf.BigFloat(v1[j - low_bound])
            v2_j = bf.BigFloat(v2[j - low_bound])
            for i in xrange(n):
                matrix[i, j] = bf.add(matrix[i, j], bf.add(bf.mul(v1_j, mul1[i]), bf.mul(v2_j, mul2[i])))
Пример #5
0
    def binary_to_range(self, point: str, precision) -> BigFloat:
        """ Bring a point from [0, 1] to a given range. """
        point = point[:precision + 2]
        interval_width = self.var_upper - self.var_lower
        bitwidth = len(point) - 2
        full_prec_context = bf.precision(bitwidth) + bf.RoundTowardNegative

        # Map to [0, 1]
        value = bf.mul(int(point, 2), bf.exp2(-bitwidth, full_prec_context), full_prec_context)
        rescaled = bf.add(bf.mul(value, interval_width, full_prec_context), self.var_lower, full_prec_context)
        return rescaled
def tridiagonal_dot_exact(tridiagonal, v, dtype=f64):
    with bf.Context(precision=EXACT_PRECISION):
        n = len(v)
        result = np.zeros(n, dtype=dtype)
        vlist = []
        for i in xrange(n):
            vlist.append(bf.BigFloat(np.float64(v[i])))
        result[0] = bf.add(bf.mul(np.float64(tridiagonal[1, 0]), vlist[0]), bf.mul(np.float64(tridiagonal[0, 1]), vlist[1]))
        for i in xrange(1, n - 1, 1):
            result[i] = bf.add(bf.add(bf.mul(np.float64(tridiagonal[2, i - 1]), vlist[i - 1]), bf.mul(np.float64(tridiagonal[1, i]), vlist[i])), bf.mul(np.float64(tridiagonal[0, i + 1]), vlist[i + 1]))
        result[n - 1] = bf.add(bf.mul(np.float64(tridiagonal[2, n - 2]), vlist[n - 2]), bf.mul(np.float64(tridiagonal[1, n - 1]), vlist[n - 1]))
        return result
Пример #7
0
def getInfo(data, target, theta):
    afterSigmoid = sigmoid(data.dot(theta))

    firstList = [ ]
    for k in afterSigmoid:
        m = []
        for x in k:
            m.append(bigfloat.log(x,bigfloat.precision(precision)))
        firstList.append(m)

    secondList = [ ]
    for k in afterSigmoid:
        m = []
        for x in k:
            m.append(bigfloat.log( bigfloat.sub(1. , x) , bigfloat.precision(precision)))
        secondList.append(m)
    
    Ein = 0.
    m = []
    for x,y in zip(firstList, secondList):
        for a,b,t in zip(x,y,target):
            value = bigfloat.add( bigfloat.mul(t[0],a, bigfloat.precision(precision)) , bigfloat.mul( bigfloat.sub(1. ,t[0], bigfloat.precision(precision)) ,a, bigfloat.precision(precision)))
            m.append(value)
    for item in m:
        Ein = bigfloat.add(item, Ein, bigfloat.precision(precision))
    
    Ein = - Ein
    print(Ein)
    gradient = -data.T.dot(target-afterSigmoid)
    return (Ein, gradient)
def partial_right_one_exact(matrix, vector, index):
    with bf.Context(precision=EXACT_PRECISION):
        n = matrix.shape[0]
        multiplier = matrix[:, index]
        for j in xrange(index + 1, n, 1):
            v_j = bf.BigFloat(np.float64(vector[j - index - 1]))
            for i in xrange(n):
                matrix[i, j] = bf.add(np.float64(matrix[i, j]), bf.mul(v_j, np.float64(multiplier[i])))
def predict_dps(prices, v_bid, v_ask, s1, s2, s3, w):

    dps = []
    w0, w1, w2, w3, w4 = w
    for i in range(120, len(prices) - 1):
        dp1 = predict_dpi(prices[i - 30:i], s1)
        dp2 = predict_dpi(prices[i - 60:i], s2)
        dp3 = predict_dpi(prices[i - 120:i], s3)
        r = (v_bid[i] - v_ask[i]) / (v_bid[i] + v_ask[i])
        dp = bg.add(
            w0,
            bg.add(
                bg.mul(w1, dp1),
                bg.add(bg.mul(w2, dp2), bg.add(bg.mul(w3, dp3), bg.mul(w4,
                                                                       r)))))
        dps.append(float(dp))
    return dps
def predict_dpi(x, s):

    num = 0
    den = 0
    for i in range(len(s)):
        y_i = s[i, len(x)]
        x_i = s[i, :len(x)]
        ex = bg.exp(-0.25 * (math.pow(euclidean_distance(x, x_i), 2)))
        num = bg.add(num, bg.mul(y_i, ex))
        den = bg.add(den, ex)
    return bg.div(num, den)
def tridiagonal_inversion_exact(tridiagonal, cell_sizes, dtype=np.float64):
    with bf.Context(precision=EXACT_PRECISION):
        sum = 0
        inverse = np.zeros(tridiagonal.shape, dtype=dtype)
        for cs in cell_sizes:
            if cs == 1:
                inverse[1, sum] = bf.div(1, np.float64(tridiagonal[1, sum]))
            else:
                a = np.float64(tridiagonal[1, sum])
                b = np.float64(tridiagonal[0, sum + 1])
                c = np.float64(tridiagonal[1, sum])
                d = np.float64(tridiagonal[1, sum + 1])
                #det = a * d - b * c
                det = bf.sub(bf.mul(a, d), bf.mul(b, c))
                inverse[1, sum] = bf.div(d, det)
                inverse[0, sum + 1] = bf.div(-c, det)
                inverse[1, sum] = bf.div(-b, det)
                inverse[1, sum + 1] = bf.div(a, det)
            sum += cs
        return inverse
Пример #12
0
 def appendZVector(self, c0):
     y = self.yvector
     z=[None]*(Params.bigo+1)
     for i in range(1,Params.bigo+1):
         k=bigfloat.mul(c0,y[i],bigfloat.precision(Params.gamma+Params.kappa))
         z[i]=float(bigfloat.mod(k,2,bigfloat.precision(Params.prec)))
         # Sometimes mod goes wrong
         if z[i]>=2.0:
             z[i]=0
     c = (c0,z)
     return c
Пример #13
0
    def degdist_bigfloat(self, maxdeg, n, mindeg=0):
        """Returns the degree distribution from 0 to maxdeg degree.

        It should be use with the (iterated) link probability measure.

        Parameters:
          maxdeg: the maximal degree for we calculate the degree distribution
          n: the size of the network (the number of vertices)

        Returns:
            rho: the degree distribution as a list with length of maxdeg+1.
                The index k gives the probability of having degree k.
        """

        assert isinstance(n, int) and isinstance(maxdeg, int) and n > maxdeg
        import bigfloat
        context = bigfloat.Context(precision=10)
        divs = self.divs
        n_intervals = len(divs)
        lengths = [divs[i] - divs[i - 1] for i in xrange(1, n_intervals)]
        lengths.insert(0, divs[0])
        log_lengths = numpy.log(lengths)
        # Eq. 5, where ...
        avgdeg = [
            bigfloat.BigFloat(n * sum(
                [self.probs[i][j] * lengths[j] for j in xrange(n_intervals)]),
                              context=context) for i in xrange(n_intervals)
        ]
        #log_factorial = [ 0.5*bigfloat.log(2*math.pi, context=context) + (d+.5)*bigfloat.log(d, context=context) - d
        #                 for d in xrange(1,maxdeg+1) ]
        log_factorial = [
            bigfloat.log(bigfloat.factorial(k), context=context)
            for k in xrange(1, maxdeg + 1)
        ]
        log_factorial.insert(0, 0)

        rho = [bigfloat.BigFloat(0, context=context)] * (maxdeg + 1)
        # Eq. 4
        for i in xrange(n_intervals):
            # Eq. 5
            log_rho_i = [
                (bigfloat.mul(k, bigfloat.log(avgdeg[i]), context=context) -
                 log_factorial[k] - avgdeg[i])
                for k in xrange(mindeg, maxdeg + 1)
            ]
            log_rho_i_length = [
                log_rho_i[k] + log_lengths[i]
                for k in xrange(mindeg, maxdeg + 1)
            ]
            for k in xrange(mindeg, maxdeg + 1):
                rho[k] += bigfloat.exp(log_rho_i_length[k], context=context)
        return rho
Пример #14
0
    def multiply(left_lower: BigFloat,
                 left_upper: BigFloat,
                 right_lower: BigFloat,
                 right_upper: BigFloat,
                 precision_of_result: int):
        context_down = bf.precision(precision_of_result) + bf.RoundTowardNegative
        context_up = bf.precision(precision_of_result) + bf.RoundTowardPositive

        # Note: inefficient to compute all pairs, Kaucher multiplication in future?
        ll_down = bf.mul(left_lower, right_lower, context_down), (left_lower, 0), (right_lower, 0)
        lu_down = bf.mul(left_lower, right_upper, context_down), (left_lower, 0), (right_upper, 1)
        ul_down = bf.mul(left_upper, right_lower, context_down), (left_upper, 1), (right_lower, 0)
        uu_down = bf.mul(left_upper, right_upper, context_down), (left_upper, 1), (right_upper, 1)

        ll_up = bf.mul(left_lower, right_lower, context_up), (left_lower, 0), (right_lower, 0)
        lu_up = bf.mul(left_lower, right_upper, context_up), (left_lower, 0), (right_upper, 1)
        ul_up = bf.mul(left_upper, right_lower, context_up), (left_upper, 1), (right_lower, 0)
        uu_up = bf.mul(left_upper, right_upper, context_up), (left_upper, 1), (right_upper, 1)

        (lower_product, (ll, ll_ind), (lr, lr_ind)) = min([ll_down, lu_down, ul_down, uu_down], key=lambda x: x[0])
        (upper_product, (ul, ul_ind), (ur, ur_ind)) = max([ll_up, lu_up, ul_up, uu_up], key=lambda x: x[0])

        # Assign derivative weights based on partial derivatives in chain rule
        llw, lrw, ulw, urw = [[0., 0.], [0., 0.], [0., 0.], [0., 0.]]
        if ll_ind == 0:
            llw[0] = float(lr)
        else:
            ulw[0] = float(lr)

        if lr_ind == 0:
            lrw[0] = float(ll)
        else:
            urw[0] = float(ll)

        if ul_ind == 0:
            llw[1] = float(ur)
        else:
            ulw[1] = float(ur)

        if ur_ind == 0:
            lrw[1] = float(ul)
        else:
            urw[1] = float(ul)
        return lower_product, upper_product, llw, lrw, ulw, urw
Пример #15
0
    def degdist_bigfloat(self, maxdeg, n, mindeg=0):
        """Returns the degree distribution from 0 to maxdeg degree.

        It should be use with the (iterated) link probability measure.

        Parameters:
          maxdeg: the maximal degree for we calculate the degree distribution
          n: the size of the network (the number of vertices)

        Returns:
            rho: the degree distribution as a list with length of maxdeg+1.
                The index k gives the probability of having degree k.
        """

        assert isinstance(n, int) and isinstance(maxdeg, int) and n > maxdeg
        import bigfloat
        context = bigfloat.Context(precision=10)
        divs = self.divs
        n_intervals = len(divs)
        lengths = [divs[i] - divs[i-1] for i in xrange(1, n_intervals)]
        lengths.insert(0, divs[0])
        log_lengths = numpy.log(lengths)
        # Eq. 5, where ...
        avgdeg = [bigfloat.BigFloat(n*sum([self.probs[i][j]*lengths[j]
                  for j in xrange(n_intervals)]), context=context) for i in xrange(n_intervals)]
        #log_factorial = [ 0.5*bigfloat.log(2*math.pi, context=context) + (d+.5)*bigfloat.log(d, context=context) - d
        #                 for d in xrange(1,maxdeg+1) ]
        log_factorial = [bigfloat.log(bigfloat.factorial(k), context=context)
                         for k in xrange(1, maxdeg+1)]
        log_factorial.insert(0, 0)

        rho = [bigfloat.BigFloat(0, context=context)] * (maxdeg+1)
        # Eq. 4
        for i in xrange(n_intervals):
            # Eq. 5
            log_rho_i = [(bigfloat.mul(k, bigfloat.log(avgdeg[i]), context=context) - log_factorial[k] - avgdeg[i])
                         for k in xrange(mindeg, maxdeg+1)]
            log_rho_i_length = [log_rho_i[k] + log_lengths[i]
                         for k in xrange(mindeg, maxdeg+1)]
            for k in xrange(mindeg, maxdeg+1):
                rho[k] += bigfloat.exp(log_rho_i_length[k], context=context)
        return rho
Пример #16
0
def Decrypt(sk,c,calcZ=True,sk1=1):
    #sk1 is for debugging purpose
    su=0
    if calcZ:
        (c0,z) = c
        for i in range(1,Params.bigo+1):
            if sk[i]!=0:
                su=bigfloat.add(su,z[i],bigfloat.precision(Params.prec))
    else:
        c0 = c
        if Keys.PK==None:
            print "Error: Z vector must be provided when public key not available"
            exit()
        y = Keys.PK[2]
        for i in range(1,Params.bigo+1):
            if sk[i]!=0:
                z = bigfloat.mul(c0,y[i],bigfloat.precision(Params.kappa))
                z = float(bigfloat.mod(z,2,bigfloat.precision(Params.prec)))
                su=bigfloat.add(su,z,bigfloat.precision(Params.prec))
    su=int(bigfloat.round(su))
    m = (c0-su) % 2
    return m
Пример #17
0
def EvaluateVector(pk,cl,ck,calcZ=True):
    (pk0,x0,y)=pk
    r=[]
    if calcZ:
        cl0=[]
        for (i,j) in cl:
            cl0.append(i)
    else:
        cl0=cl
    
    ck.setReductionVector(x0)  #This is added to Trees constructor
    r0 = ck.eval(cl0)
    if calcZ:
        for c0 in r0:
            z=[None]*(Params.bigo+1)
            for i in range(1,Params.bigo+1):
                k=bigfloat.mul(c0,y[i],bigfloat.precision(Params.kappa))
                z[i]=float(bigfloat.mod(k,2,bigfloat.precision(Params.prec)))
            c = (c0,z)
            r.append(c)
    else:
        r=r0
    return r
Пример #18
0
def Encrypt(pk,m,calcZ=True,s=None):
    #s is the secret key to be used for debugging purposes
    (pk0,x,y)=pk
    c0 = SomeWhatEncrypt((pk0,x), m)
    if calcZ:
        z=[None]*(Params.bigo+1)
        for i in range(1,Params.bigo+1):
            k=bigfloat.mul(c0,y[i],bigfloat.precision((Params.kappa+Params.gamma)))
            z[i]=float(bigfloat.mod(k,2.0,bigfloat.precision(Params.prec)))
            if z[i]>=2.0:
                z[i]=0
        c = (c0,z)
    else:
        c = c0
    if debug:
        su=0
        for i in range(1,Params.bigo+1):
            if s and s[i]==1:
                su=bigfloat.add(su,z[i],bigfloat.precision(Params.kappa+Params.gamma))
        print "Enc_sum%2=",bigfloat.mod(su,8,bigfloat.precision((Params.prec+Params.gamma)))
        q=bigfloat.div(c0,globsk,bigfloat.precision(Params.kappa+Params.gamma))
        print "(Enc_c/sk)%2=",bigfloat.mod(q,8,bigfloat.precision((Params.prec+Params.gamma)))
        print "c0=",c0
    return c
from bigfloat import sub, add, mul, div, sqr, sqrt, precision

a=1e-8
b=10
c=1e-8
p = 100

D = sub(sqr(b) , mul(4, mul(a,c) ), precision(p))

x1 = div( - add(b , sqrt(D, precision(p))) , mul(2,a), precision(p))
x2 = div( - sub(b , sqrt(D, precision(p))) , mul(2,a), precision(p))

print x1,x2
Пример #20
0
def KeyGen(Lambda):
    global globsk #For debugginh
    (sk0,pk0)=SomeWhatKeyGen(Lambda)
    globsk = sk0  #For debugging
    #Params.kappa = int(Params.gamma * Params.eta / Params.rho1)
    
    '''Tweak to approximate to nearest integer'''
    t=sk0/2+1
    xp=int((2**Params.kappa+t)/sk0) # Approximating to nearest integer
    S = []
    lenS=0
    while lenS!=Params.theta:
        i=random.randrange(1,Params.bigo)
        if i not in S:
            S.append(i)
            lenS+=1
    s={}
    for i in range(1,Params.bigo+1):
        if i in S:
            s[i]=1
        else:
            s[i]=0
    
    n = 2**(Params.kappa)      
    m = 2**(Params.kappa+1)
    u = {}
    approx = xp/Params.theta
    var = approx/Params.theta
    for i in range(1,Params.bigo+1):
        u[i]=random.randrange(0,m)
    su=0
    for i in S[:-1]:
        x =random.randrange(approx-var,approx+var)
        u[i]=x
        su+=u[i]
    i=S[-1]
    u[i]=xp-su
    
    y={}
    for i in range(1,Params.bigo+1):
        y[i]=bigfloat.div(u[i],n,bigfloat.precision((Params.kappa+Params.gamma)))
    #DEBUG
    if debug:
        su = 0
        su2=0
        for i in S:
            su2+=u[i]
            su=bigfloat.add(su,y[i],bigfloat.precision(Params.kappa+Params.gamma))
            inv = bigfloat.mul(n,y[i],bigfloat.precision(Params.kappa+Params.gamma))
            print u[i]
            print inv
        print "sumxp=",su2
        print "sumf=",su
        print "xp=", xp
        print "xp/n=", bigfloat.div(xp,n,bigfloat.precision(Params.kappa+Params.gamma))
        print "m=",m
        print Params.theta
        print Params.bigo
        print S
        print s
    #END DEBUG
    (pk1,x)=pk0
    pk = (pk1,x,y)
    return (s,pk)
def bunch_kaufman_exact(mtx_origin, alpha=(1. + sqrt(17)) / 8, regularize=False, regularize_coeff=1e-4):
    dtype = mtx_origin.dtype
    mtx = np.array(mtx_origin, dtype=dtype)
    n = mtx.shape[0]
    tridiagonal = np.zeros([3, n], dtype=dtype)
    sum = 0
    cell_sizes = []
    PL = I(n, dtype=dtype)
    flip = False
    while sum < n:
        m = n - sum
        mtx_view = mtx[sum: n, sum: n]
        if sum >= n - 2:
            if sum == n - 2:
                cell_sizes.append(2)
                tridiagonal[1, sum], tridiagonal[1, sum + 1] = mtx_view[0, 0], mtx_view[1, 1]
                tridiagonal[0, sum + 1] = mtx_view[0, 1]
                tridiagonal[2, sum] = mtx_view[1, 0]
            else:
                tridiagonal[1, sum] = mtx_view[0, 0]
            break
        if flip:
            mtx_view[:, :] = mtx_view[::-1, ::-1]
            PL[:, sum:] = PL[:, :sum - 1:-1]
        idx = np.argmax(np.abs(mtx_view.diagonal()))
        swap_indices = (0, idx)
        triangular = I(n, dtype=dtype)
        triangular_view = triangular[sum: n, sum: n]

        exchange_rows(mtx_view, swap_indices[0], swap_indices[1])
        exchange_columns(mtx_view, swap_indices[0], swap_indices[1])
        exchange_columns(PL, swap_indices[0] + sum, swap_indices[1] + sum)

        idx = np.argmax(np.abs(mtx_view[:, 0]))
        lambda_val = abs(mtx_view[:, 0][idx])
        if abs(mtx_view[0, 0]) >= alpha * lambda_val:
            n_k = 1
            swap_indices = (0, 0)
        else:
            testing_column = np.abs(mtx_view[:, idx])
            testing_column[idx] = 0
            j_idx = np.argmax(testing_column)
            sigma_val = testing_column[j_idx]

            if sigma_val * abs(mtx_view[0][0]) >= alpha * lambda_val**2:
                n_k = 1
                swap_indices = (0, 0)
            else:
                if abs(mtx_view[idx][idx]) >= alpha * sigma_val:
                    n_k = 1
                    swap_indices = (0, idx)
                else:
                    n_k = 2
                    assert idx != j_idx, 'please check your factorization. This indices MUST be different'
                    swap_indices = (1, idx)
        if n_k == 2:
            exchange_rows(mtx_view, 0, j_idx)
            exchange_columns(mtx_view, 0, j_idx)
            exchange_columns(PL, sum + 0, sum + j_idx)
        exchange_rows(mtx_view, swap_indices[0], swap_indices[1])
        exchange_columns(mtx_view, swap_indices[0], swap_indices[1])
        exchange_columns(PL, sum + swap_indices[0], sum + swap_indices[1])

        T_k = mtx_view[0:n_k, 0:n_k]
        if n <= sum + n_k:
            if n_k == 1:
                tridiagonal[1, sum] = T_k[0, 0]
            else:
                tridiagonal[1, sum], tridiagonal[1, sum + 1] = T_k[0, 0], T_k[1, 1]
                tridiagonal[0, sum + 1] = T_k[0, 1]
                tridiagonal[2, sum] = T_k[1, 0]
            cell_sizes.append(n_k)
            break
        T_k_inverse = inverse_1_2_exact(T_k, dtype=dtype)
        B_k = mtx_view[n_k: m, 0: n_k]
        triangular_view[n_k: m, 0: n_k] = dot(-B_k, T_k_inverse)

        PL_view = PL[sum:n, sum:n]
        if n_k == 1:
            tridiagonal[1, sum] = T_k[0, 0]
            tri_one = triangular_view[1: m, 0]
            tri_one = -B_k[:, 0] * T_k_inverse[0, 0]
            """print '-'*80
            print 'mtx before left mul'
            print mtx_view"""
            partial_left_one_exact(mtx_view, tri_one, 0)
            """print '-'*80
            print 'mtx before right mul, after left'
            print mtx_view"""
            partial_right_one_exact(mtx_view, tri_one, 0)
            # print '-'*80
            # print 'mtx after right mul'
            # print mtx_view
            # print '-'*80
            mtx_view[1: m, 0] = 0
            mtx_view[0, 1: m] = 0
            # print '-'*80
            # print 'PL before right mul'
            # print PL
            # print '-'*80
            tri_one = -tri_one
            with bf.Context(precision=EXACT_PRECISION):
                for i in xrange(n):
                    ssum = bf.BigFloat(0)
                    for j in xrange(sum + 1, n, 1):
                        ssum = bf.add(ssum, bf.mul(np.float64(PL[i, j]), np.float64(tri_one[j - sum - 1])))

                    PL[i, sum] = bf.add(np.float64(PL[i, sum]), ssum)
                #PL[i, sum] += dot(PL[i, sum + 1:n], (-tri_one))
            # print '-'*80
            # print 'PL after right mul'
            # print PL
            # print '-'*80
        else:
            B_k_minus = -B_k

            tridiagonal[1, sum], tridiagonal[1, sum + 1] = T_k[0, 0], T_k[1, 1]
            tridiagonal[0, sum + 1] = T_k[0, 1]
            tridiagonal[2, sum] = T_k[1, 0]
            tri_one = np.zeros(m)
            tri_two = np.zeros(m)
            for i in xrange(m):
                tri_one[i] = bf.add(bf.mul(B_k_minus[i, 0], T_k_inverse[0, 0]), bf.mul(B_k_minus[i, 1], T_k_inverse[1, 0]))
                tri_two[i] = bf.add(bf.mul(B_k_minus[i, 0], T_k_inverse[0, 1]), bf.mul(B_k_minus[i, 1], T_k_inverse[1, 1]))
            #tri_one = triangular_view[2: m, 0]
            #tri_two = triangular_view[2: m, 1]
            """print '-'*80
            print 'mtx before left mul'
            print mtx_view"""
            partial_left_two_exact(mtx_view, tri_one, tri_two, 0, 1)
            """print '-'*80
            print 'mtx before right mul, after left'
            print mtx_view"""
            partial_right_two_exact(mtx_view, tri_one, tri_two, 0, 1)
            """print '-'*80
            print 'mtx after right mul'
            print mtx_view
            print '-'*80"""
            mtx_view[2: m, [0, 1]] = 0
            mtx_view[[0, 1], 2: m] = 0
            """print '-'*80
            print 'PL before right mul'
            print PL
            print '-'*80"""
            with bf.Context(precision=EXACT_PRECISION):
                tri_one = -tri_one
                tri_two = -tri_two
                for i in xrange(n):
                    ssum1 = bf.BigFloat(0)
                    ssum2 = bf.BigFloat(0)
                    for j in xrange(sum + 2, n, 1):
                        ssum1 = bf.add(ssum1, bf.mul(PL[i, j], tri_one[j - sum - 2]))
                        ssum2 = bf.add(ssum2, bf.mul(PL[i, j], tri_two[j - sum - 2]))

                    PL[i, sum] = bf.add(PL[i, sum], ssum1)
                    PL[i, sum + 1] = bf.add(PL[i, sum + 1], ssum2)
            """print '-'*80
            print 'PL after right mul'
            print PL
            print '-'*80"""
        sum += n_k
        cell_sizes.append(n_k)
        #flip = not flip
    #print 'ASSEMBLED:'
    #print dot(dot(PL, mtx), np.matrix(PL).getH())
    P, L = separate_permutation(PL, dtype=dtype)

    return P, L, cell_sizes, tridiagonal