# Imports
import numpy as np
import gurobipy as gbp
import datetime as dt

#  Constants
Aij = np.random.randint(5, 50, 400)
Aij = Aij.reshape(20,20)
AijSum = np.sum(Aij)
Cj = np.random.randint(10, 20, 20)
CjSum = np.sum(Cj)
Bi = np.random.randint(10, 20, 20)
BiSum = np.sum(Bi)

# Matrix Shape
rows = range(len(Aij))
cols = range(len(Aij[0]))


"""
Explanation: <font size='5' face='Courier New'><h1 align="center"><i>The Primal & Dual Linear Programming Problems: Canonical Form</i></h1></font> 
<font face='Times New Roman' size='6'><h3 align="center"><u>James&nbsp;D.&nbsp;Gaboardi</u></h3></font>

<font face='Times New Roman' size='5'><h3 align="center">Florida State University &nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp; Department of Geography</h3></font>


<p><font size='4' face='Times New Roman'>Adapted from:</font></p>
<p><font size='4' face='Times New Roman'><b>Daskin, M. S.</b> 1995. <i>Network and Discrete Location: Models, Algorithms, and Applications</i>. Hoboken, NJ, USA: John Wiley & Sons, Inc.</font></p>


<font size='7' face='Times New Roman'><b>0. <u>Imports and Data Creation</u></b></font>
End of explanation
"""


def GbpPrimCan():    
    # Instantiate Model
    mPrimal_Canonical_GUROBI = gbp.Model(' -- Canonical Primal Linear Programming Problem -- ')

    # Set Focus to Optimality
    gbp.setParam('MIPFocus', 2)

    # Decision Variables
    desc_var = []
    for dest in cols:
        desc_var.append([])
        desc_var[dest].append(mPrimal_Canonical_GUROBI.addVar(vtype=gbp.GRB.CONTINUOUS, 
                                        name='y'+str(dest+1)))
    # Update Model
    mPrimal_Canonical_GUROBI.update()

    #Objective Function
    mPrimal_Canonical_GUROBI.setObjective(gbp.quicksum(Cj[dest]*desc_var[dest][0] 
                            for dest in cols), 
                            gbp.GRB.MINIMIZE)
    # Constraints
    for orig in rows:
        mPrimal_Canonical_GUROBI.addConstr(gbp.quicksum(Aij[orig][dest]*desc_var[dest][0] 
                            for dest in cols) - Bi[orig] >= 0)
    # Optimize
    try:
        mPrimal_Canonical_GUROBI.optimize()
    except Exception as e:
        print '   ################################################################'
        print ' < ISSUE : ', e, ' >'
        print '   ################################################################'
    # Write LP file
    mPrimal_Canonical_GUROBI.write('LP.lp')
    print '\n*************************************************************************'
    print '    |   Decision Variables'
    for v in mPrimal_Canonical_GUROBI.getVars():
        print '    |  ', v.VarName, '=', v.x
    print '*************************************************************************'
    val = mPrimal_Canonical_GUROBI.objVal
    print '    |   Objective Value ------------------ ', val
    print '    |   Aij Sum -------------------------- ', AijSum
    print '    |   Cj Sum --------------------------- ', CjSum
    print '    |   Bi Sum --------------------------- ', BiSum
    print '    |   Matrix Dimensions ---------------- ', Aij.shape
    print '    |   Date/Time ------------------------ ', dt.datetime.now()
    print '*************************************************************************'
    print '-- Gurobi Canonical Primal Linear Programming Problem --'
    
try:
    GbpPrimCan()
    print '\nJames Gaboardi, 2015'
except Exception as e:
    print '   ################################################################'
    print ' < ISSUE : ', e, ' >'
    print '   ################################################################'

"""
Explanation: <font size='7' face='Times New Roman'><b>1. <u>Primal</u></b></font>
End of explanation
"""


def GbpDualCan():    
    # Instantiate Model
    mDual_Canonical_GUROBI = gbp.Model(' -- Canonical Dual Linear Programming Problem -- ')

    # Set Focus to Optimality
    gbp.setParam('MIPFocus', 2)

    # Decision Variables
    desc_var = []
    for dest in cols:
        desc_var.append([])
        desc_var[dest].append(mDual_Canonical_GUROBI.addVar(vtype=gbp.GRB.CONTINUOUS, 
                                        name='u'+str(dest+1)))
    # Update Model
    mDual_Canonical_GUROBI.update()

    #Objective Function
    mDual_Canonical_GUROBI.setObjective(gbp.quicksum(Bi[orig]*desc_var[orig][0] 
                            for orig in rows), 
                            gbp.GRB.MAXIMIZE)
    # Constraints
    for dest in cols:
        mDual_Canonical_GUROBI.addConstr(gbp.quicksum(Aij[orig][dest]*desc_var[dest][0] 
                            for orig in rows) - Cj[dest] <= 0)
    # Optimize
    try:
        mDual_Canonical_GUROBI.optimize()
    except Exception as e:
        print '   ################################################################'
        print ' < ISSUE : ', e, ' >'
        print '   ################################################################'
    # Write LP file
    mDual_Canonical_GUROBI.write('LP.lp')
    print '\n*************************************************************************'
    print '    |   Decision Variables'
    for v in mDual_Canonical_GUROBI.getVars():
        print '    |  ', v.VarName, '=', v.x
    print '*************************************************************************'
    val = mDual_Canonical_GUROBI.objVal
    print '    |   Objective Value ------------------ ', val
    print '    |   Aij Sum -------------------------- ', AijSum
    print '    |   Cj Sum --------------------------- ', CjSum
    print '    |   Bi Sum --------------------------- ', BiSum
    print '    |   Matrix Dimensions ---------------- ', Aij.shape
    print '    |   Date/Time ------------------------ ', dt.datetime.now()
    print '*************************************************************************'
    print '-- Gurobi Canonical Dual Linear Programming Problem --'
    
try:
    GbpDualCan()
    print '\nJames Gaboardi, 2015'
except Exception as e:
    print '   ################################################################'
    print ' < ISSUE : ', e, ' >'
    print '   ################################################################'

"""
Explanation: <font size='7' face='Times New Roman'><b>2. <u>Dual</u></b></font>
End of explanation
"""


