from acsploit.options import Options

options = Options()
options.add_option('order', 2, 'Order n of linear program (aka number of equations)')
options.add_option('mu', 3.0, 'Determines `shape` of constraint region (Must be >= 3.0; Epsilon = 1/mu)')
options.add_option('pivot_type', 'largest_coefficient', 'Choice of pivot rule',
                   ['largest_coefficient', 'smallest_index'])


DESCRIPTION = 'Produces a worst-case input (Klee-Minty) for the simplex algorithm for linear programming.' \
              '\n\n  Klee-Minty examples have exponential runtime for classical pivot rules.' \
              'Examples taken from Linear Programming: Klee-Minty Examples by Konstantinos Paparrizos, ' \
              'Nikolaos Samaras, and Dimitrios Zissopoulos'

NO_INPUT = True


def run(output):  # generates worst case input to the classic simplex algorithm (as shown by Klee and Minty)
    ret = get_simplex(options['order'], options['mu'], options['pivot_type'])
    output.output(ret)


def get_simplex(order, mu, pivot_type):
    if mu < 3.0:
        raise ValueError('mu must be at least 3.0')
    if pivot_type == 'smallest_index':
        mu = 1/mu  # convert mu to epsilon
    c = [0 for _ in range(order)]
    A = [[0 for _ in range(order)] for _ in range(order)]
    b = [1 for _ in range(order)]
    A[0][0] = 1
    for i in range(order):
        c[i] = -mu ** (order-i-1)
        A[i][i] = 1
        for j in range(0, i):
            if i > 0:
                A[i][j] = 2 * mu ** (i-j)
        if pivot_type == 'largest_coefficient':
            b[i] = mu**(2*i)
    return [c, A, b]
