Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Dan committed Oct 13, 2020
0 parents commit 31face8
Show file tree
Hide file tree
Showing 22 changed files with 1,627 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
__pycache__/
scratch/
build/
dist/
*.egg-info/
scratch.py
674 changes: 674 additions & 0 deletions LICENSE.txt

Large diffs are not rendered by default.

73 changes: 73 additions & 0 deletions OR/BigM.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
from pandas import DataFrame
import numpy as np
from .Format import *
from .TableauBase import TableauBase

def getRep(num,M_val):
# solve for integer M values, the rest... soz
round5 = lambda x: round(x,5)
if abs(num%M_val) < abs(num%-M_val):
#kM+x
mNo = int((num - num%M_val)/M_val)
defNo = num%M_val
else:
#KM-x
mNo = int((num - num%-M_val)/M_val)
defNo = num%-M_val

mNo = round5(mNo)
defNo = round5(defNo)

if mNo == 1:
mString = " M "
elif mNo == -1:
mString = "-M "
elif mNo == 0:
mString = ""
else:
mString = f"{mNo}M "

if defNo == 0:
defString = ""
elif defNo > 0:
defString = f"+{defNo}"
else:
defString = f"{defNo}"
if mString + defString == "":
return 0
else:
return mString + defString

class BigM(TableauBase):
@classmethod
def fromLP(cls,inLP,M_Val = 1e6):
constraintSigns = inLP.posRHS().body.loc[:,"signs"]
baseT = super().fromLP(inLP)
body = baseT.dataFrame
basicVar = list(baseT.basicVar)
aVals = []
for i in range(1,len(constraintSigns)):
if constraintSigns[i] in (">","="):
newCol = [0] * body.shape[0]
newCol[0] = M_Val
newCol[i] = 1
body.insert(body.shape[1]-1,f"a{subscript(i)}",newCol)
basicVar[i] = f"a{subscript(i)}"

return BigM(body,tuple(basicVar),aVals,M_Val=M_Val)

def fromTableauBase(self,base):
return BigM(base.dataFrame,base.basicVar,self.aVals)

def __init__(self,dataFrame,basicVar,aVals,M_Val=1e6):
super().__init__(dataFrame,basicVar,dispFunc = lambda x: getRep(x,M_Val))
self.aVals = aVals # list of a factors
# self.dispFunc =

def canonical(self,echo=False):
t = super().canonical(echo=echo)
return self.fromTableauBase(t)

def solve(self,echo=False):
t = super().solve(echo=echo)
return self.fromTableauBase(t)
46 changes: 46 additions & 0 deletions OR/CommonLP.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
from .LP import LP

class CommonLP():
def __init__(self):
pass

@classmethod
def bevco(cls):
return LP.new(
["min", 2, 3],
[[0.5, 0.25, "<", 4],
[1, 3, ">", 20],
[1, 1, "=", 10], ],
[">", ">"],
factorNames=False)

@classmethod
def bevcoInf(cls):
return LP.new(
["min", 2, 3],
[[0.5, 0.25, "<", 4],
[1, 3, ">", 36],
[1, 1, "=", 10], ],
[">", ">"],
factorNames=False)

@classmethod
def dakota(cls):
return LP.new(
["max", 60, 30, 20],
[[8, 6, 1, "<", 48],
[4, 2, 1.5, "<", 20],
[2, 1.5, 0.5, "<", 8],
[0, 1, 0, "<", 5]],
[">", ">", ">"],
factorNames=False)

@classmethod
def dakotaDual(cls):
return LP.new(
["min", 48, 20, 8, 5],
[[8, 4, 2, 0, ">", 60],
[6, 2, 1.5, 1, ">", 30],
[1, 1.5, 0.5, 0, ">", 20], ],
[">", ">", ">", ">"],
factorNames=["Y₁", "Y₂", "Y₃", "Y₄"])
19 changes: 19 additions & 0 deletions OR/Format.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
try:
from ipython import display
except:
pass
def subscript(i):
# ima let you toggle between subscript and full height numbers
# return i
out = ""
for j in str(i):
out +=chr(ord(u'\u2080')+ int(j))
return out
# LP Object
# duality finding method
def displayHelper(item):
#display works on jupyter but might not always be included?
try:
display(item)
except:
print(item)
148 changes: 148 additions & 0 deletions OR/LP.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
from pandas import DataFrame
from pandas import Series
import numpy as np
from .Format import *

class Constraint():
def __init__(self):
self.variables = variables # 1d dataFrame
self.sign = sign # String
self.RHS = RHS # number

@classmethod
def fromArray(cls,variables,sign,RHS,names=False):
if not names:
names = [f"X{subscript(i+1)}"for i in range(variables)]
variables = DataFrame(variables,columns=names)
return Constraint(variables,sign,RHS)


class LP():
@classmethod # raw constructor
def new(cls,objectiveFn,constraints,signs,factorNames = False):
#throw in some error checking to ensure valid LP
objectiveType = objectiveFn[0]
if not factorNames:
factorNames = [f"X{subscript(i+1)}" for i in range(len(objectiveFn)-1)]
factorNames = factorNames + ["signs","RHS"]
body = DataFrame(
[objectiveFn[1:]+["",""]]+
constraints,
columns=factorNames)
return LP(objectiveType,body,signs)

def __init__(self,objectiveType,body,signs):
self.objectiveType = objectiveType # String
self.body = body # DataFrame
self.signs = signs # List

def getDual(self,newFactorName = "Y"):
if self.objectiveType == "min":
constraint_sign = {">":">","=":"urs","<":"<"}
variable_sign = {">":"<","urs":"=","<":">"}
else:
constraint_sign = {"<":">","=":"urs",">":"<"}
variable_sign = {">":">","urs":"=","<":"<"}
objectiveType = "min"if self.objectiveType == "max" else "max"

body = self.body.copy()
signs = self.signs.copy()

obj = body.iloc[:,-1:].T.drop(0,axis=1)
mid = body.iloc[:,:-2].drop(0).T
obj = obj.append(mid).reset_index().drop("index",axis=1)
obj.columns = [f"{newFactorName}{subscript(i)}" for i in obj.columns]
obj.insert(obj.shape[1],"signs",np.array([""] + [variable_sign[i] for i in signs]))
obj.insert(obj.shape[1],"RHS",np.append([""],body.iloc[0,:-2]))

newSigns = list(body.loc[:,"signs"])[1:]
newSigns = [constraint_sign[i] for i in newSigns]
return LP(objectiveType,obj,newSigns)

def getStandardForm(self):
#set positive signs
posSigns = self.posSigns()
#modify urs factors
noURS = posSigns.clearURS()
#add surplus/slack variables
SFactors = noURS.addSFactors()

#set positive RHS
return SFactors.posRHS()
def posSigns(self):
'''Set the X<0 factors to X>0'''
objectiveType = self.objectiveType
body = self.body.copy()
signs = self.signs.copy()
for i in range(len(signs)):
if signs[i] == "<":
signs[i] = ">"
body.iloc[:,i] = body.iloc[:,i].apply(lambda x: x*-1)
return LP(objectiveType,body,signs)
def clearURS(self):
objectiveType = self.objectiveType
body = self.body.copy()
signs = self.signs.copy()
i = 0
while i < len(signs):
if signs[i] == "urs":
signs[i] = ">"
signs.insert(i,">")
body.insert(i+1,body.columns[i]+"'",body.iloc[:,i])
body.insert(i+2,body.columns[i]+"\"",body.iloc[:,i]*-1)
body = body.drop(body.columns[i],axis=1)
i+=1
return LP(objectiveType,body,signs)
def addSFactors(self):
objectiveType = self.objectiveType
body = self.body.copy()
signs = self.signs.copy()
for i in range(1,body.shape[0]):
if body.iloc[i].loc["signs"] == "<":
newCol = [0] * body.shape[0]
newCol[i] = 1
body.insert(body.shape[1]-2,f"s{subscript(i)}",np.array(newCol))
signs.insert(body.shape[1]-2,">")
elif body.iloc[i].loc["signs"] == ">":
newCol = [0] * body.shape[0]
newCol[i] = -1
body.insert(body.shape[1]-2,f"s{subscript(i)}",np.array(newCol))
signs.insert(body.shape[1]-2,">")
body.iloc[i] = body.iloc[i].apply(lambda x: "=" if x in [">","<"] else x)
return LP(objectiveType,body,signs)
def posRHS(self):
objectiveType = self.objectiveType
body = self.body.copy()
signs = self.signs.copy()
for i in range(1,body.shape[0]):
row = body.iloc[i]
if row.loc["RHS"]<=0:
body.iloc[i] = body.iloc[i].apply(lambda x: x*-1 if type(x)!=str else x)
return LP(objectiveType,body,signs)

def __eq__(self,other):
if all(self.body.eq (other.body)):
return True
else:
return False

def display(self):
outDF = self.body.copy()
outDF.insert(0,"",[1]+[""]*(len(self.body)-1))
outDF.iloc[0,0] = self.objectiveType
for i in outDF.columns[1:-2]:
outDF.loc[:,i] = (outDF.loc[:,i].apply(lambda x: "" if x==0 else x))
outDF.loc[:,i] = (outDF.loc[:,i].apply(str))
outDF.loc[:,i] = (outDF.loc[:,i].apply(lambda x: x if (len(x)==0 or x[0]=="-") else "+"+x))
outDF.loc[:,i] = (outDF.loc[:,i].apply(lambda x: x if len(x)==0 else x+i))

signsDF = DataFrame([[""] + self.signs+["",""]],columns = outDF.columns)
for i in signsDF.columns[1:-2]:
signsDF.loc[:,i] = (signsDF.loc[:,i].apply(lambda x: i + x + " 0" if x in [">","<"] else x))
signsDF.loc[:,i] = (signsDF.loc[:,i].apply(lambda x: i + " " + x if x =="urs" else x))
outDF = outDF.append(signsDF)
outDF = outDF.reset_index().drop(["index"],axis=1)
return outDF

def __repr__(self):
return str(self.display())
Loading

0 comments on commit 31face8

Please sign in to comment.