def bisection(a, b, fn, e):
    """
    S vyuzitim metody Bisekcie vypocita koren funkcie fn na intervale <a,b>.
    """

    assert a < b, 'Cislo b musi byt vacsie ako cislo a'
    assert e > 0, 'Presnost e musi byt vacsia ako nula'

    f = lambda x: eval_expr(fn, x=x)

    while True:
        # stred intervalu <a,b>
        x = 0.5 * (a + b)

        logger.info('a = {0}, b = {1}, x = {2}'.format(a, b, x))

        # skonci ak je stred intervalu
        # korenom funkcie inak uprav interval
        if f(x) == 0:
            return x
        elif f(a) * f(x) < 0:
            b = x
        else:
            a = x

        # skonci pri dosiahnuti presnosti
        if b - a <= e:
            return x
def gaussseidel(a, b, x, e):
    """
    S vyuzitim Gauss Seidelovej metody vypocita sustavu linearnych rovnic.
    Matica a reprezentuje lavu stranu sustavy, matica b vektor pravej
    strany a matica x reprezentuje vektor aproximacie.

    Priklad:

    Nevyhovujuca:
    a = Matrix((
        [1,1,-3],
        [2,5,1],
        [4,-1,2],
    ))
    b = [-4,5,-12]

    Vyhovujuca:
    a = Matrix((
        [11,2,1],
        [1,10,2],
        [2,3,-8],
    ))
    b = [15,16,1]
    """

    assert a.rows == len(b) == len(x), \
    'Rozmery matice "a" a pocet prvkov vo vektoroch "b" a "x" ' \
    'musi byt rovnaky'

    assert e > 0, 'Presnost e musi byt vacsia ako nula'
    assert check_norms(a), 'Matica nesplna konvergencne kriterium'

    # novy vektor aproximacie
    x1 = list(x)

    while True:
        for i in range(a.rows):
            sum_a = sum_b = 0

            for j in range(i):
                sum_a += a[i, j] * x1[j]

            for j in range(i + 1, a.rows):
                sum_b += a[i, j] * x[j]

            # vypocet dalsej aproximacie
            x1[i] = (1 / a[i, i]) * (b[i] - sum_a - sum_b)

        # vypocet rozdielu prvej a druhej aproximacie (norma)
        error = norm_error(x1, x)

        logger.info('x1 = {0}\nx = {1}\nerror = {2}\n'.format(
            list_as_float(x1), list_as_float(x), float(error)))

        # skonci pri dosiahnuti presnosti
        if error <= e:
            return list_as_float(x1)

        x = list(x1)
def leastsquares(x, fx):
    """
    S vyuzitim metody najmensich stvorcov urci priamku
    blizko predpisanym hodnotam.
    """

    # pocet x
    n = len(x)

    assert n == len(fx), 'Dlzka listov x a fx musi byt rovnaka'

    # suma 1 * n
    sum_1 = n

    # suma vsetkych x
    sum_x = sum(x)

    # suma vsetkych mocnin x
    sum_x2 = sum([i**2 for i in x])

    # suma vsetkych fx
    sum_fx = sum(fx)

    # suma vsetkych x * fx
    sum_x_fx = sum(xi * fxi for xi, fxi in zip(x, fx))

    logger.info(
        'sum_1 = {0}, sum_x = {1}, sum_x2 = {2}, sum_fx = {3}, sum_x_fx = {4}\n'
        .format(sum_1, sum_x, sum_x2, sum_fx, sum_x_fx))

    # lava strana sustavy
    a = Matrix((
        [sum_1, sum_x],
        [sum_x, sum_x2],
    ))

    # prava strana sustavy
    b = [sum_fx, sum_x_fx]

    # aproximacia riesenia pre jacobiho metodu
    x = [0, 0]

    # jacobiho metodou vypocita sustavu
    c1, c2 = jacobi(a, b, x, e=0.01)

    return '{0} + {1}x'.format(c1, c2)
def trapezoid(a, b, m, fn, e):
    """
    Na intervale <a,b>, ktory sa rozdeli na m lichobeznikov, vypocita
    aproximaciu urciteho integralu funkcie fn.
    """

    assert a < b, 'Cislo b musi byt vacsie ako cislo a'
    assert e > 0, 'Presnost e musi byt vacsia ako nula'

    f = lambda x: eval_expr(fn, x=x)
    I = []
    J1 = 0
    J2 = 0
    k = 0

    # rozdelenie intervalu na m rovnako dlhych dielov
    h = (b - a) / m

    for i in range(m):
        J1 += f(a + (h * i))
        J2 += f(a + h * (i + 1))

    I.append((h / 2) * (J1 + J2))

    while True:
        J1 = 0
        J2 = 0
        m *= 2

        # skratenie intervalu na polovicu
        h /= 2

        for i in range(m):
            J1 += f(a + (h * i))
            J2 += f(a + h * (i + 1))

        I.append((h / 2) * (J1 + J2))

        logger.info('m = {0}, h = {1}, Abs(I[k] - I[k + 1]) = {2}'.format(
            m, h, I[k] - I[k + 1]))

        # skonci pri dosiahnuti presnosti
        if Abs(I[k] - I[k + 1]) <= e:
            return I[k + 1]

        k += 1
def babylon(n, x0, e):
    """
    S vyuzitim Babylonskej metody vypocita odmocninu cisla n.
    """

    assert n > 0, 'Cislo n musi byt vacsie ako nula'
    assert x0 > 0, 'Pociatocna hodnota x0 musi byt vacsia ako nula'
    assert e > 0, 'Presnost e musi byt vacsia ako nula'

    while True:
        # nova aproximacia je priemerom hodnot x0 a n / x0
        x = 0.5 * (x0 + n / x0)

        logger.info(
            'x = {0}, x0 = {1}, Abs(x - x0) = {2}'.format(x, x0, Abs(x - x0)))

        # skonci ak je dosiahnuta pozadovana presnost
        if Abs(x - x0) < e:
            return x

        x0 = x
def newton(a, b, fn, e):
    """
    S vyuzitim Newtonovej metody vypocita koren funkcie fn na intervale <a,b>.
    """

    assert a < b, 'Cislo b musi byt vacsie ako cislo a'
    assert e > 0, 'Presnost e musi byt vacsia ako nula'

    # urci prvu a druhu derivaciu funkcie
    fn_d1 = diff(fn)
    fn_d2 = diff(fn_d1)

    logger.info('fn_d1 = {0}, fn_d2 = {1}'.format(fn_d1, fn_d2))

    f = lambda x: eval_expr(fn, x=x)
    fd = lambda x: eval_expr(fn_d1, x=x)
    fd2 = lambda x: eval_expr(fn_d2, x=x)

    # aspon jeden z bodov musi splnit podmienku
    # inak je potrebne upravit interval
    if f(a) * fd2(a) > 0:
        x = a
    elif f(b) * fd2(b) > 0:
        x = b
    else:
        raise ValueError('aspon jeden z bodov a alebo b musi '
                         'splnat podmienku f(x) * fd2(x) > 0')

    while True:
        # vypocet priesecnika s osou x
        x1 = x - f(x) / fd(x)

        logger.info(
            'x = {0}, x1 = {1}, Abs(x1 - x) = {2}'.format(x, x1, Abs(x1 - x)))

        # skonci pri dosiahnuti presnosti
        if Abs(x1 - x) <= e:
            return x1

        x = x1