-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Dan
committed
Oct 13, 2020
0 parents
commit 31face8
Showing
22 changed files
with
1,627 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
__pycache__/ | ||
scratch/ | ||
build/ | ||
dist/ | ||
*.egg-info/ | ||
scratch.py |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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₄"]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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()) |
Oops, something went wrong.