'''
# cogirth-packing gap of projections of graphic matroids

K_{2,2}   gap ≈ 3/2      column = (0, 0, 0, 0)
K_{2,3}   gap ≈ 3/2      column = (1, 0, 1, 1, 1)
K_{2,4}   gap ≈ 2        column = (0, 0, 1, 1, 1, 1)
K_{2,5}   gap ≈ 2        column = (1, 0, 1, 1, 1, 1, 1)
K_{2,6}   gap ≈ 2        column = (1, 1, 1, 1, 1, 1, 1, 1)
K_{2,7}   gap ≈ 2        column = (1, 0, 1, 1, 1, 1, 1, 1, 1)
K_{2,8}   gap ≈ 2        column = (0, 0, 1, 1, 1, 1, 1, 1, 1, 1)
K_{2,9}   gap ≈ 2        column = (1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1)
K_{3,3}   gap ≈ 16/9     column = (1, 1, 1, 1, 1, 1)
K_{3,4}   gap ≈ 5/3      column = (0, 0, 0, 1, 1, 1, 1)
K_{3,5}   gap ≈ 12/5     column = (1, 1, 1, 1, 1, 1, 1, 1)
K_{3,6}   gap ≈ 7/3      column = (0, 0, 0, 1, 1, 1, 1, 1, 1)
K_{3,7}   gap ≈ 16/7     column = (1, 0, 0, 1, 1, 1, 1, 1, 1, 1)
K_{3,8}   gap ≈ 9/4      column = (1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1)
K_{3,9}   gap ≈ 20/9     column = (1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
K_{4,4}   gap ≈ 9/4      column = (1, 1, 1, 1, 1, 1, 1, 1)
K_{4,5}   gap ≈ 7/4      column = (1, 0, 0, 0, 1, 1, 1, 1, 1)
K_{4,6}   gap ≈ 8/3      column = (1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
K_{4,7}   gap ≈ 9/4      column = (1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1)
'''

from sage.all import *
from sage.matroids.all import *
from sage.graphs.all import *
import gurobipy as gp
from gurobipy import GRB
from fractions import Fraction

env = gp.Env(empty=True)
env.setParam("OutputFlag",0)
env.start()

def representative_vectors(m, n):
    for w1 in range(m+1):
        for w2 in range(n+1):
            v = [0]*(m+n)
            v[:w1] = [1]*w1
            v[m:m+w2] = [1]*w2
            yield tuple(v)

def cogirthip(bases, integral=true):
    model = gp.Model("mip1",env=env)
    # model.Params.LogToConsole = 0
    groundset=frozenset()
    for B in bases: groundset=groundset|frozenset(B)
    x = dict()
    if integral:
        for e in groundset: x[e]=model.addVar(vtype=GRB.BINARY)
    else:
        for e in groundset: x[e]=model.addVar(vtype=GRB.CONTINUOUS,lb=0)
    model.setObjective(gp.quicksum([x[e] for e in groundset]), GRB.MINIMIZE)
    for B in bases:
        model.addConstr(gp.quicksum([x[e] for e in B])>=1)
    model.optimize()
    return model.ObjVal


# cnt=0   # actual number of instances tested
# f = lambda g: g.is_connected()
for N in range(2,10):
    for M in range(N,10):
        g=graphs.CompleteBipartiteGraph(N,M)
        A=g.incidence_matrix()
        n,m = A.dimensions()
        maxgap = 0
        for v in representative_vectors(N,M):
            # cnt=cnt+1
            v_col=matrix(v).transpose()
            A_t=A.augment(v_col)
            # print(A_t)
            MM=Matroid(matrix=A_t,field=GF(2))/m     #contract the last element
            # print(M)
            bases=MM.bases()
            strength=cogirthip(bases,integral=false)
            cogirth =cogirthip(bases,integral=true)
            gap = cogirth/strength
            if gap > maxgap:
                maxgap = gap
                maxcol = v
        frac=str(Fraction(maxgap).limit_denominator(m))
        print(f"K_{{{N},{M}}}   gap ≈ {frac:<8} column = {maxcol}")
