#!/usr/bin/python 

from pyCmpl import *

import sys
import os
import time
#import cStringIO
#import thread 
#import threading
import tempfile
import shutil
#import traceback
 

class TppException(Exception):
    pass

#Big M used for the TPP mode
bigM = 1000000000

#*************** SourceElement *************************************
class Source(object):
        #*********** constructor **********
        def __init__(self):
                self.__idx = 0
                self.__name = ""
                self.__xPos = 0
                self.__yPos = 0
                self.__minSupply = 0
                self.__supply = 0
                self.__maxSupply = 0
                self.__flow = 0 
        #*********** end constructor ******
        
        # getter and setter 
        @property
        def idx(self):
                return self.__idx
        
        def setIdx(self, idx):
                if type(idx)==int or type(idx)==int:
                        self.__idx = idx
                else:
                        if not CmplTools.strIsNumber(idx.strip()):
                                raise TppException("Wrong index <" +str( idx)+ "> "  )
                        else:
                                self.__idx=int(idx)
        
        @property
        def name(self):
                return self.__name
        
        def setName(self, name):
                self.__name = name
                
        @property
        def xPos(self):
                return self.__xPos
               
        def setXPos(self, pos):
            if type(pos)==float:
                    self.__xPos = pos
            else:
                    tmpPos=pos.strip().replace(',','.')
                    try:
                        self.__xPos=float(tmpPos)
                    except:
                        raise TppException("Wrong xPosition <" +str( pos)+  "> "  )
                
        @property
        def yPos(self):
                return self.__yPos
           
        def setYPos(self, pos):
                if type(pos)==float:
                        self.__yPos = pos
                else:
                        tmpPos=pos.strip().replace(',','.')
                        try:
                            self.__yPos=float(tmpPos) 
                        except:
                            raise TppException("Wrong yPosition <" +str( pos)+ "> "  )
       
        @property
        def supply(self):
                return self.__supply 
        
        def setSupply(self, supply):
                if type(supply)==int or type(supply)==float or type(supply)==int:
                        self.__supply  = supply
                else:
                        if CmplTools.strIsNumber(supply.strip()):
                                self.__supply=int(supply)
                        else:
                                raise TppException("Wrong supply <"+str( supply)+ "> "  )
                        
        @property
        def minSupply(self):
                return self.__minSupply 
        
        def setMinSupply(self, supply):
                if type(supply)==int or type(supply)==float or type(supply)==int:
                        self.__minSupply  = supply
                else:
                        if CmplTools.strIsNumber(supply.strip()):
                                self.__minSupply=int(supply)
                        else:
                                raise TppException("Wrong min supply <"+str( supply)+ "> "  )
        @property
        def maxSupply(self):
                return self.__maxSupply 
        
        def setMaxSupply(self, supply):
                if type(supply)==int or type(supply)==float or type(supply)==int:
                        self.__maxSupply  = supply
                else:
                        if supply.strip().upper() == "M":
                                self.__maxSupply = bigM
                        elif CmplTools.strIsNumber(supply.strip()):
                                self.__maxSupply=int(supply)
                        else:
                                raise TppException("Wrong max supply <"+str( supply)+ "> "  )
                
        @property
        def maxSupplyString(self):
                sTmp=''
                if self.__maxSupply!=bigM:
                        sTmp=str( int(self.__maxSupply))
                else:
                        sTmp='M'
                return sTmp
                        
        @property
        def flow(self):
                return self.__flow
        
                
        def incFlow(self, flow):
                if type(flow)==int or type(flow)==float or type(flow)==int:
                        self.__flow += flow
                else:
                        if not CmplTools.strIsNumber(flow.strip()):
                                raise TppException("Wrong flow <" +str( flow)+  "> "  )
                        else:
                                self.__flow+=int(flow)  
        
#*************** end SourceElement **********************************



#*************** DestinationElement *************************************
class Destination(object):
        #*********** constructor **********
        def __init__(self):
                self.__idx = 0
                self.__name = ""
                self.__xPos = 0
                self.__yPos = 0
                self.__demand = 0
                self.__minDemand = 0
                self.__maxDemand = bigM
                self.__flow = 0

        #*********** end constructor ******
        
        # getter and setter 
        @property
        def idx(self):
                return self.__idx
        
        def setIdx(self, idx):
                if type(idx)==int or type(idx)==int:
                        self.__idx = idx
                else:
                        if not CmplTools.strIsNumber(idx.strip()):
                                raise TppException("Wrong index <" +str( idx)+ "> "  )
                        else:
                                self.__idx=int(idx)
                
        @property
        def name(self):
                return self.__name
        
        def setName(self, name):
                self.__name = name
                
        @property
        def xPos(self):
                return self.__xPos
               
        def setXPos(self, pos):
            if type(pos)==float:
                    self.__xPos = pos
            else:
                    tmpPos=pos.strip().replace(',','.')
                    try:
                        self.__xPos=float(tmpPos)
                    except:
                        raise TppException("Wrong xPosition <" +str( pos)+  "> "  )
                
        @property
        def yPos(self):
                return self.__yPos
           
        def setYPos(self, pos):
                if type(pos)==float:
                        self.__yPos = pos
                else:
                        tmpPos=pos.strip().replace(',','.')
                        try:
                            self.__yPos=float(tmpPos) 
                        except:
                            raise TppException("Wrong yPosition <" +str( pos)+ "> "  )
                
        @property
        def demand(self):
                return self.__demand 
        
        def setDemand(self, dem):
                if type(dem)==int or type(dem)==float or type(dem)==int:
                        self.__demand = dem
                else:
                        if not CmplTools.strIsNumber(dem.strip()):
                                raise TppException("Wrong demand <" +str(dem)+  "> "  )
                        else:
                                self.__demand=int(dem)
                                
        @property
        def minDemand(self):
                return self.__minDemand 
        
        def setMinDemand(self, dem):
                if type(dem)==int or type(dem)==float or type(dem)==int:
                        self.__minDemand = dem
                else:
                        if not CmplTools.strIsNumber(dem.strip()):
                                raise TppException("Wrong min demand <" +str(dem)+  "> "  )
                        else:
                                self.__minDemand=int(dem)
                                
        @property
        def maxDemand(self):
                return self.__maxDemand 
        
        def setMaxDemand(self, dem):
                if type(dem)==int or type(dem)==float or type(dem)==int:
                        self.__maxDemand = dem
                else:
                        
                        if dem.strip().upper() == "M":
                                self.__maxDemand = bigM
                        elif CmplTools.strIsNumber(dem.strip()):
                                self.__maxDemand=int(dem)
                        else:
                                raise TppException("Wrong max demand <" +str(dem)+  "> "  )
                        
        @property
        def maxDemandString(self):
                sTmp=''
                if self.__maxDemand!=bigM:
                        sTmp=str( int(self.__maxDemand))
                else:
                        sTmp='M'
                return sTmp
                                
        @property
        def flow(self):
                return self.__flow
        
                
        def incFlow(self, flow):
                if type(flow)==int or type(flow)==float or type(flow)==int:
                        self.__flow += flow
                else:
                        if not CmplTools.strIsNumber(flow.strip()):
                                raise TppException("Wrong flow <" +str( flow)+  "> "  )
                        else:
                                self.__flow+=int(flow)  
                        
#*************** end DestinationElement **********************************


#*************** CmplWLP  ************************************************
class TPP(object):
        
        #*********** constructor **********
        def __init__(self,LogLabHomePath, tppFile,  llVersion ):

                self.__home = LogLabHomePath  
                cmplHomePath =  LogLabHomePath + 'Cmpl' 

                os.environ.update({'CMPLHOME': cmplHomePath })

                self.__LogLabVersion=llVersion
                
                self.__sources = []
                self.__destinations = []
                self.__edges = []
                self.__fixedEdges = []
                
                
                self.__comment = 0
                
                self.__nrOfDestinationsInHeader = 0
                self.__nrOfSourcesInHeader = 0
                
                self.__totalSupply = 0
                self.__totalDemand = 0
                self.__flow = 0
                
                #self.__totalDemand = 0
                #self.__totalCapa = 0
                
                self.__srcIdx=0
                self.__destIdx=0
                
                self.__costs = []
                self.__fixCosts = []
                self.__caps = []

                #self.__costTol = 0.6
                #self.__maxCost = 0
                #self.__avgCost = 0
                #self.__maxMinCost = 0

                self.__costTolAdder = 0
                self.__maxCostSrc = []
                self.__minCostSrc = []
                self.__avgCostSrc = []
                self.__costTolSrc = []

                
                self.__tppFile = tppFile
                
                #self.__solutionStatus = ""
                #self.__solutionFound = False
                                
                self.__model = None
                
                self.__modelType = 0 # 0 -standard  1- bottleneck -
                self.__objSense = 0 #0 -min 1 - max
                
                self.__isCapCon = False
                self.__isSupplyCon = False
                self.__isDemandCon = False
                self.__isSingleSourceCon = False
                self.__isFixedCosts = False
                
                self.__isBlockCon = False
                self.__minBlock = 0
                self.__maxBlock = bigM
                
                self.__mipGap = 0

                self.__tmpPath = tempfile.gettempdir()+os.sep
                self.__solFile = self.__tmpPath + os.path.splitext(os.path.basename(tppFile))[0]+".SOLX"
                
                self.__NodeHeuristics = 100
               
                self.__mipGap = 0.001

                self.__debug = False
                                
        #*********** end constructor ******
        
        #*********** readTppFile ************
        def readTppFile(self):
                        
                optSection = False              
                sourcesSection = False
                destSection = False
                costSection = False
                fixedCostSection = False
                capSection = False

                #nrCosts = 0
                #sumCosts = 0
                
                if not os.path.isfile(self.__tppFile):
                        raise TppException("File does not exist <" + self.__tppFile +">" )
                                        
                try:    
                        f = open(self.__tppFile, "r",encoding='utf8')
                        
                        lineNr = 0
                        secLineNr=0
                        for line in f:
                                lineNr+=1
                                if lineNr == 1:
                                        if line.lstrip().upper()[0:3] != "TPP" :
                                                raise TppException("File is not a TPP file <" + self.__tppFile +">" )
                                        continue
                                elif lineNr==2:
                                        self.__comment=line
                                        continue
                                else:
                                        if line.strip().upper().startswith("OPTION") :
                                                optSection = True               
                                                sourcesSection = False
                                                destSection = False
                                                costSection = False
                                                fixedCostSection = False
                                                capSection = False
                                                continue
                                        elif line.strip().upper().startswith("SOURCES")  :
                                                optSection = False              
                                                sourcesSection = True
                                                destSection = False
                                                costSection = False
                                                fixedCostSection = False
                                                capSection = False
                                                secLineNr=0
                                                self.__srcIdx=0
                                                continue
                                        elif line.strip().upper().startswith("DESTINATIONS"):
                                                optSection = False              
                                                sourcesSection = False
                                                destSection = True
                                                costSection = False
                                                fixedCostSection = False
                                                capSection = False
                                                secLineNr=0
                                                self.__destIdx=0
                                                continue
                                        elif line.strip().upper().startswith("COSTS"):
                                                optSection = False              
                                                sourcesSection = False
                                                destSection = False
                                                costSection = True
                                                fixedCostSection = False
                                                capSection = False
                                                continue
                                        elif line.strip().upper().startswith("FIXEDCOSTS"):
                                                optSection = False              
                                                sourcesSection = False
                                                destSection = False
                                                costSection = False
                                                fixedCostSection = True
                                                capSection = False
                                                continue
                                        elif line.strip().upper().startswith("CAPACITIES"):
                                                optSection = False              
                                                sourcesSection = False
                                                destSection = False
                                                costSection = False
                                                fixedCostSection = False
                                                capSection = True
                                                continue
                                        elif line.strip().upper().startswith("EEE"):
                                                optSection = False              
                                                sourcesSection = False
                                                destSection = False
                                                costSection = False
                                                fixedCostSection = False
                                                capSection = False
                                                continue
                                
                                if optSection:
                                        if line.strip().upper().startswith("OBJECTIVESENSE") :
                                                obj = line.split('\t')[1].upper()
                                                if obj.startswith("MINIMAX"):
                                                        self.__objSense = 2
                                                elif obj.startswith("MAXIMIN"):
                                                        self.__objSense = 3
                                                elif obj.startswith("MIN"):
                                                        self.__objSense = 0
                                                elif obj.startswith("MAX"):
                                                        self.__objSense = 1
                                                                                        
                                        if line.strip().upper().startswith("KEYFIGURE") :
                                                if line.split('\t')[1].upper().strip()=='VARANDFIXEDCOSTS' :
                                                        self.__isFixedCosts = True
                                                else:
                                                        self.__isFixedCosts = False
                                                continue
                                        
                                        if line.strip().upper().startswith("TYPE") :
                                                if line.split('\t')[1].upper().strip()=='STANDARD' :
                                                        self.__modelType = 0
                                                elif  line.split('\t')[1].upper().strip()=='BOTTLENECK' :
                                                        self.__modelType = 1
                                                else:
                                                        self.__modelType = 0
                                                continue
                                        
                                        if line.strip().upper().startswith("BLOCKING") :
                                                e=line.split('\t')
                                                
                                                if not CmplTools.strIsNumber(e[1].strip()):
                                                        raise TppException("Wrong lower bound for cost blocking constraint <" + str(e[1])+ "> in file <" +self.__tppFile+ "> in line <" +str( lineNr) + ">" )
                                                else:
                                                        self.__minBlock=float(e[1].strip())
                                                
                                                if e[2].strip().upper()=='M':
                                                        self.__maxBlock = bigM
                                                elif not CmplTools.strIsNumber(e[2].strip()):
                                                        raise TppException("Wrong upper bound for cost blocking constraint <" + str(e[1])+ "> in file <" +self.__tppFile+ "> in line <" +str( lineNr) + ">" )
                                                else:
                                                        self.__maxBlock=float(e[2].strip())
                                                        
                                                self.__isBlockCon = True
                                                continue
                                        
                                        if line.strip().upper().startswith("SUBJECTTO") :
                                                e=line.split('\t')
                                                if e[1].strip().upper()=='SUPPLYRANGES':
                                                        self.__isSupplyCon = True
                                                elif  e[1].strip().upper()=='DEMANDRANGES':
                                                        self.__isDemandCon = True
                                                elif  e[1].strip().upper()=='CAPACITIES':
                                                        self.__isCapCon = True
                                                elif  e[1].strip().upper()=='SINGLESOURCE':
                                                        self.__isSingleSourceCon = True
                                                continue
                                                
                                        
                                if sourcesSection:
                                        secLineNr+=1
                                        if secLineNr==1:
                                                if not CmplTools.strIsNumber(line.strip()):
                                                        raise TppException("Wrong number of sources <"+ line + "> in file <" + self.__tppFile +"> in line <"+str(lineNr)+ ">" )
                                                
                                                self.__nrOfSourcesInHeader=int(line.strip())
                                                continue
                                        elif secLineNr==2:
                                                continue
                                        else:
                                                e=line.split('\t')
                                                self.__srcIdx+=1
                                                if len(e)!=12:
                                                        raise TppException("Wrong entry for a source <"+ line + "> in file <" + self.__tppFile +"> in line <"+str(lineNr)+ ">" )
                                                else:
                                                        try:
                                                                s = Source()
                                                                s.setIdx(self.__srcIdx)
                                                                s.setName(e[1])
                                                                s.setXPos(e[2])
                                                                s.setYPos(e[3])
                                                                s.setSupply(e[9])
                                                                s.setMinSupply(e[10])
                                                                s.setMaxSupply(e[11])
                                                                
                                                                self.__totalSupply += s.supply
                                                                
                                                        except Exception as e:
                                                                raise TppException("Wrong entry for a source <"  +str( e)+  "> in file <" + self.__tppFile +"> in line <"+str(lineNr)+ ">" )
                                                        
                                                        self.__sources.append(s)
                                        continue
                                
                                if destSection:
                                        secLineNr+=1
                                        if secLineNr==1:
                                                if not CmplTools.strIsNumber(line.strip()):
                                                        raise TppException("Wrong number of destinations <"+ line + "> in file <" + self.__tppFile +"> in line <"+str(lineNr)+ ">" )
                                                
                                                self.__nrOfDestinationsInHeader=int(line.strip())
                                                continue
                                        elif secLineNr==2:
                                                continue
                                        else:
                                                e=line.split('\t')
                                                self.__destIdx+=1
                                                if len(e)!=12:
                                                        raise TppException("Wrong entry for a destination <"+ line + "> in file <" + self.__tppFile +"> in line <"+str(lineNr)+ ">" )
                                                else:
                                                        try:
                                                                d = Destination()
                                                                d.setIdx(self.__destIdx)
                                                                d.setName(e[1])
                                                                d.setXPos(e[2])
                                                                d.setYPos(e[3])
                                                                d.setDemand(e[9])
                                                                d.setMinDemand(e[10])
                                                                d.setMaxDemand(e[11])
                                                                
                                                                self.__totalDemand += d.demand
                                                                                                                
                                                        except TppException as e:
                                                                raise TppException("Wrong entry for a destination <" +str( e) + "> in file <" + self.__tppFile+ "> in line <" +str(lineNr)+ ">" )
                                                        
                                                        self.__destinations.append(d)
                                        continue
                                                        
                                if costSection:
                                        costStringList = line.strip().split('\t')
                                        if len(costStringList) != self.__destIdx:
                                                raise TppException("Wrong costs for a source in file <" + self.__tppFile +"> in line <", lineNr,">" )
                                        
                                        costList = []

                                        minCost = bigM
                                        maxCost = 0 
                                        avgCost = 0
                                        sumCosts = 0
                                       
                                        for c in costStringList:
                                                if c.strip().upper() == "M":
                                                        costList.append(bigM)
                                                elif CmplTools.strIsNumber(c.strip()):
                                                        cost = float(c)
                                                        costList.append(cost)

                                                        if cost>maxCost:
                                                                maxCost=cost
                                                        sumCosts += cost
                                                        if cost < minCost:
                                                                minCost  = cost
                                                        
                                                else:
                                                        raise TppException("Wrong cost <" + str(c)+ "> in file <" +self.__tppFile+ "> in line <" +str( lineNr) + ">" )
                                                
                                        #if minCost>self.__maxMinCost:
                                        #        self.__maxMinCost=minCost      


                                        self.__costs.append(costList)
                                        self.__minCostSrc.append(minCost)
                                        self.__maxCostSrc.append(maxCost)
                                        avgCost = sumCosts/len(self.__destinations)
                                        self.__avgCostSrc.append(avgCost)

                                        continue
                                        
                                        
                                if fixedCostSection:
                                        costStringList = line.strip().split('\t')
                                                                        
                                        if len(costStringList) != self.__destIdx:
                                                raise TppException("Wrong fixed costs for a source in file <" + self.__tppFile +"> in line <", lineNr,">" )
                                        
                                        costList = []
                                        for c in costStringList:
                                                if c.strip().upper() == "M":
                                                        costList.append(bigM)
                                                elif CmplTools.strIsNumber(c.strip()):
                                                        costList.append(float(c))
                                                else:
                                                        raise TppException("Wrong cost <" + str(c)+ "> in file <" +self.__tppFile+ "> in line <" +str( lineNr) + ">" )
                                        
                                        self.__fixCosts.append(costList)
                                        continue
                                
                                
                                if capSection:
                                        capStringList = line.strip().split('\t')
                                        if len(capStringList) != self.__destIdx:
                                                raise TppException("Wrong capacities for a source in file <" + self.__tppFile +"> in line <", lineNr,">" )
                                        
                                        capList = []
                                        for c in capStringList:
                                                if c.strip().upper() == "M":
                                                        capList.append(bigM)
                                                elif CmplTools.strIsNumber(c.strip()):
                                                        capList.append(int(c))
                                                else:
                                                        raise TppException("Wrong capacities <" + str(c)+ "> in file <" +self.__tppFile+ "> in line <" +str( lineNr) + ">" )
                                        self.__caps.append(capList)
                                        continue
                                                        
                        f.close()
                        
                        if self.__nrOfDestinationsInHeader != self.__destIdx:
                                raise TppException("Wrong number of destinations " )
                
                        if self.__nrOfSourcesInHeader != self.__srcIdx:
                                raise TppException("Wrong number of sources " )
                        
                        if self.__objSense > 1 and self.__isFixedCosts:
                                raise TppException("Bottleneck and fixed cost cannot be combined" )
                        
                        if self.__objSense == 3:
                                raise TppException("Bottleneck max is not implemented" )
                        
                        if len(self.__caps)==0:
                                for i in range(self.__srcIdx):
                                        self.__caps.append(  [ bigM for  j in range(self.__destIdx) ]  )
                                        
                        if len(self.__fixCosts)==0:
                                for i in range(self.__srcIdx):
                                        self.__fixCosts.append(  [ 0 for  j in range(self.__destIdx) ]  )
                                
                        #self.__avgCost = sumCosts/nrCosts
                                                        
                except IOError as e:
                        raise TppException("Can't read TPP File <" + self.__tppFile +">  <" +str( e)+">" )
                
        #*********** end readTppFile ************       

        def __setCostTol(self):
                factor = 1.25
                for i,s in enumerate(self.__sources):  
                        if self.__avgCostSrc[i] > self.__minCostSrc[i]:
                                self.__costTolSrc.append( self.__avgCostSrc[i]/self.__maxCostSrc[i] * factor)
                        else: 
                                self.__costTolSrc.append( self.__minCostSrc[i]/self.__maxCostSrc[i] * factor )


        #*********** __setEdges     ************
        def __setEdges(self ):

                self.__edges = []
                self.__vCosts = []
                self.__fCosts = []
                self.__capacities = []
                                
                for ii,s in enumerate(self.__sources):
                        self.__costTolSrc[ii] += self.__costTolAdder
                        maxCost = self.__maxCostSrc[ii] * self.__costTolSrc[ii] 

                        for d in self.__destinations:
                                i = s.idx-1
                                j = d.idx-1

                                if self.__costs[i][j] <= maxCost and self.__costs[i][j] >= self.__minBlock and self.__costs[i][j]<= self.__maxBlock and self.__costs[i][j]<bigM:
                                        self.__edges.append((i+1,j+1))
                                        
                                        self.__vCosts.append(self.__costs[i][j]) 

                                        if self.__isFixedCosts:
                                                self.__fCosts.append(self.__fixCosts[i][j])
                                        else:
                                                self.__fCosts.append(0)

                                        if self.__isCapCon:
                                                self.__capacities.append(self.__caps[i][j])
                                        else:
                                                self.__capacities.append(bigM)
                self.__checkEdges()

        #*********** __setEdges     ************
                                                
        def __checkEdges(self):
                
                for d in self.__destinations:
                        destAssigned = False
                        for s in self.__sources:
                                i = s.idx
                                j = d.idx
                                if (i,j) in self.__edges:
                                         destAssigned = True
                                         break
                        
                        if not destAssigned:
                                for s1 in self.__sources:
                                        i = s1.idx
                                        j = d.idx
                                        self.__edges.append((i,j))
                                        i-=1
                                        j-=1
                                        self.__vCosts.append(self.__costs[i][j]) 
                                        if self.__isFixedCosts:
                                                self.__fCosts.append(self.__fixCosts[i][j])
                                        else:
                                                self.__fCosts.append(0)
                                        if self.__isCapCon:
                                                self.__capacities.append(self.__caps[i][j])
                                        else:
                                                self.__capacities.append(bigM)




        #*********** __fixVariables  ************

        def __fixVariables(self):
                self.__fixedEdges = []

                for i,j in self.__edges:
                        try:
                                '''if self.__model.y[(i,j)].activity == 0:
                                        if random.random()<self.__fixVarProb:
                                                self.__fixedEdges.append((i,j))'''
                               
                                if self.__model.y[(i,j)].activity == 0:
                                        if abs(self.__model.supplies[i].marginal) == 0:
                                        #        self.__fixedEdges.append((i,j))
                                        #else:
                                                if random.random()<self.__fixVarProb:
                                                        self.__fixedEdges.append((i,j))      
                        except Exception as err:
                                raise TppException("Error while fixing vars <" +str( err)+">" )
                                #pass


        #*********** __fixVariables  ************

        def __checkCostTol(self):
                ok = False
                for tol in self.__costTolSrc:
                        if tol < 1:
                                ok = True
                return ok


        #*********** solve ************
        def solve(self, timeLimit=300):

                sTime=time.time()

                self.__nrOfNodes = self.__srcIdx + self.__destIdx

                if self.__mipGap == 0:

                        if self.__nrOfNodes < 50:
                                self.__mipGap = 0
                        elif self.__nrOfNodes < 100:
                                self.__mipGap = 0.01
                        elif self.__nrOfNodes < 150:
                                self.__mipGap = 0.02
                        else:
                                self.__mipGap = 0.02
           
                if self.__isFixedCosts and len(self.__fixCosts)==0: 
                        raise TppException("No fixed cost data for fixed cost problem" )        
                
                if self.__isCapCon and len(self.__caps)==0:
                        raise TppException("No fixed cost data for capacitated problem" )   
                         
                
                self.__fixedEdges= [(-1,-1)]
                fEdges = CmplSet("fixedEdges",2)
                fEdges.setValues(self.__fixedEdges )

                sources = CmplSet("sources")
                sources.setValues(1,self.__srcIdx)
                
                destinations = CmplSet("destinations")
                destinations.setValues(1,self.__destIdx)
                        
                totalDemand=0
                totalSupply=0
                
                minSupplyVals=[]
                maxSupplyVals=[]
                minDemandVals=[]
                maxDemandVals=[]
                                
                for source in self.__sources:
                        if self.__isSupplyCon:
                                minSupplyVals.append(source.minSupply)
                                maxSupplyVals.append(source.maxSupply)
                                totalSupply+=source.maxSupply
                        else:
                                minSupplyVals.append(0)
                                maxSupplyVals.append(source.supply)
                                totalSupply+=source.supply
                
                minS = CmplParameter('minS', sources)
                minS.setValues(minSupplyVals)
                maxS = CmplParameter('maxS', sources)
                maxS.setValues(maxSupplyVals)
                        
                for dest in self.__destinations:
                        if self.__isDemandCon:
                                minDemandVals.append(dest.minDemand)
                                maxDemandVals.append(dest.maxDemand)
                                totalDemand+=dest.maxDemand
                        else:
                                minDemandVals.append(0)
                                maxDemandVals.append(dest.demand)
                                totalDemand+=dest.demand
                
                minD = CmplParameter('minD', destinations)
                minD.setValues(minDemandVals)
                maxD = CmplParameter('maxD', destinations)
                maxD.setValues(maxDemandVals)
                
                objSense = CmplParameter('objSense')
                objSense.setValues(self.__objSense)
                
                            
                valMode = CmplParameter('valueMode')
                if totalDemand<totalSupply:
                        valMode.setValues(0)
                elif totalDemand>totalSupply:
                        valMode.setValues(1)
                else:
                        valMode.setValues(2)
                        
                maxBlock = CmplParameter('maxBlock')      
                minBlock = CmplParameter('minBlock')
                costBlockMode = CmplParameter('costBlockMode')
                if self.__isBlockCon:
                        costBlockMode.setValues(1)
                        minBlock.setValues(self.__minBlock)
                        maxBlock.setValues(self.__maxBlock)
                else:
                        costBlockMode.setValues(0)
                        minBlock.setValues(0)
                        maxBlock.setValues(bigM)

                singleSourceMode = CmplParameter('singleSourceMode')
                if self.__isSingleSourceCon:
                        singleSourceMode.setValues(1)
                else:
                        singleSourceMode.setValues(0)
                                     
                supplyConMode = CmplParameter('supplyConMode')
                if self.__isSupplyCon:
                        supplyConMode.setValues(1)
                else:
                        supplyConMode.setValues(0)
                
                demandConMode = CmplParameter('demandConMode')
                if self.__isDemandCon:
                        demandConMode.setValues(1)
                else:
                        demandConMode.setValues(0)
                
                relaxedMode = CmplParameter('relaxedMode')
                relaxedMode.setValues(1)
                        
                bM = CmplParameter("M")
                bM.setValues(bigM)
                        
                modelName = self.__home + 'CmplApps'+os.sep+'tpp.cmpl'
                shutil.copyfile(modelName, self.__tmpPath+"tpp.cmpl") 
                modelName=self.__tmpPath+"tpp.cmpl" 

                if (self.__isFixedCosts or self.__isSingleSourceCon or self.__objSense == 2 ) and self.__nrOfNodes > self.__NodeHeuristics: 
                #if self.__nrOfNodes > 30: 
                     
                        print ('    ... solving relaxtion ')

                        self.__costTolAdder = 0
                        self.__setCostTol()

                        while True:
                                self.__model = Cmpl(modelName)
                                self.__model.debug(self.__debug)
                                self.__model.setOutput(False)

                                print (f'        ... with cost tolerance adder of {self.__costTolAdder} ')

                                self.__setEdges()

                                edges = CmplSet("edges",2)
                                edges.setValues(self.__edges)

                                costs = CmplParameter("c", edges )
                                costs.setValues(self.__vCosts)

                                fixedCostMode = CmplParameter('fixedCostMode')
                                if self.__isFixedCosts:
                                        fixedCostMode.setValues(1)
                                else:
                                        fixedCostMode.setValues(0)
                                fc = CmplParameter("fc",edges )
                                fc.setValues(self.__fCosts)

                
                                caps = CmplParameter("caps",edges )
                                caps.setValues(self.__capacities)

                                self.__model.setSets(fEdges, edges, sources,destinations)
                
                                self.__model.setParameters( objSense,valMode,fixedCostMode,singleSourceMode,supplyConMode,demandConMode)
                                self.__model.setParameters(costs, bM , minS,maxS,minD,maxD, caps,fc, relaxedMode)
                                self.__model.setParameters(costBlockMode, minBlock, maxBlock)
                        
                                self.__model.setOption('-solver highs') 
                                self.__model.solve()

                                if self.__model.solverStatus != SOLVER_OK:   
                                        print('        ... No solution has been found') 
                                        if not self.__checkCostTol():
                                                raise TppException(' No solution has been found with relaxation')
                                else:
                                        print(f'        ... Solution has been found with obj value {self.__model.solution.value} ') 
                                        break

                                self.__costTolAdder += 0.1
                                
                                if (time.time()-sTime) > timeLimit:
                                        raise TppException(' No solution has been found  with relaxation')
                        
                        print ('    ... solving fixed model ')
               
                        self.__fixVarProb = 0.6
                        self.__fixVariables()

                        fEdges.setValues(self.__fixedEdges )
                        relaxedMode.setValues(0)

                        self.__model = Cmpl(modelName)

                        timeLimit -= round(time.time()-sTime)
                        if timeLimit<0:
                                raise TppException('No solution has been found with relaxation')


                        self.__model.setOption('-solver highs')   
                        self.__model.setOption(f'-opt highs time_limit={timeLimit}')  
                        self.__model.setOption(f'-opt highs mip_rel_gap={self.__mipGap}')  
                        self.__model.setOption(f'-opt scip limits/time={timeLimit}')  
                        self.__model.setOption(f'-opt scip limits/gap={self.__mipGap}')  
                        self.__model.setOption(f'-opt cbc sec={timeLimit}')   
                        self.__model.setOption(f'-opt cbc ratio={self.__mipGap}') 

                        self.__model.setSets(fEdges, edges, sources,destinations)
                
                        self.__model.setParameters( objSense,valMode,fixedCostMode,singleSourceMode,supplyConMode,demandConMode)
                        self.__model.setParameters(costs, bM , minS,maxS,minD,maxD, caps,fc, relaxedMode)
                        self.__model.setParameters(costBlockMode, minBlock, maxBlock)
                        

                        self.__model.debug(self.__debug)
                        self.__model.solve()  

                        if self.__model.solverStatus != SOLVER_OK:   
                                raise TppException('No solution has been found')
                        else:
                                print(f'    ... Solution has been found with obj value {self.__model.solution.value} ') 
                        
                else:
                        print ('    ... solving model ')

                        self.__costTolAdder = 1
                        self.__setCostTol()

                        #für exakte Loesung ein maxCost=M setzen
                        self.__setEdges()

                        edges = CmplSet("edges",2)
                        edges.setValues(self.__edges)

                        costs = CmplParameter("c", edges )
                        costs.setValues(self.__vCosts)

                        fixedCostMode = CmplParameter('fixedCostMode')
                        if self.__isFixedCosts:
                                fixedCostMode.setValues(1)
                        else:
                                fixedCostMode.setValues(0)
                        fc = CmplParameter("fc",edges )
                        fc.setValues(self.__fCosts)

                        caps = CmplParameter("caps",edges )
                        caps.setValues(self.__capacities)

                        relaxedMode.setValues(0)

                        self.__model = Cmpl(modelName)
                        self.__model.setSets(fEdges, edges, sources,destinations)
                        self.__model.setParameters( objSense,valMode,fixedCostMode,singleSourceMode,supplyConMode,demandConMode)
                        self.__model.setParameters(costs, bM , minS,maxS,minD,maxD, caps,fc, relaxedMode)
                        self.__model.setParameters(costBlockMode, minBlock, maxBlock)
                                                
                        self.__model.debug(self.__debug)
                        self.__model.setOutput(False)
                        self.__model.solve()  

                        if self.__model.solverStatus != SOLVER_OK:   
                                raise TppException('No solution has been found')
                        else:
                                print(f'    ... Solution has been found with obj value {self.__model.solution.value} ') 
                        


                #self.__model.solutionReport()
                                
                try:    
                        os.remove( modelName)
                except:
                        pass

                
                
        #*********** end solve **************
        
        #*********** __intToStrM  ************
        def __intToStrM(self, num):
                sTmp=''
                if num!=bigM:
                        sTmp=str( int(num))
                else:
                        sTmp='M'
                return sTmp
        #*********** __intToStrM ************
        
        #*********** __intToStr  ************
        def __intToStr(self, num):
                return str( int(num))
        #*********** __intToStr ************

        #*********** __intToStrM  ************
        def __floatToStrM(self, num):
                sTmp=''
                if num!=bigM:
                        sTmp=str( num )
                else:
                        sTmp='M'
                return sTmp
        #*********** __intToStrM ************
        
        #*********** __intToStr  ************
        def __floatToStr(self, num):
                return str( num )
        #*********** __intToStr ************
        

        
        #*********** writeSolFile ************
        def writeSolFile(self):
                
                try:
                        f = open(self.__solFile, "w")
                        
                        now = time.localtime()
                        
                        f.write("TPP %s SOLUTION       %g.%g.%g    %g:%g:%g\n" % (self.__LogLabVersion,now.tm_mday , now.tm_mon, now.tm_year , now.tm_hour, now.tm_min, now.tm_sec) ) 
                        
                        f.write(self.__comment.strip()+"\n")
                        f.write('Sources:\t%g\n' % (self.__nrOfSourcesInHeader))
                        f.write('Destinations:\t%g\n' % (self.__nrOfDestinationsInHeader))
                        
                        f.write('Supply:\t%20.0f\n' % (self.__totalSupply))
                        f.write('Demand:\t%20.0f\n' % (self.__totalDemand))
                        f.write('Gap:\t%g\n' % (self.__totalSupply-self.__totalDemand))
                        
                        if self.__modelType==0:
                                f.write('Type:\tStandard\n' )
                        else:
                                f.write('Type:\tBottleneck\n' )
                                
                        
                        sTmp='Objective:\t'     
                        if self.__objSense==0:
                                if self.__modelType==0:
                                        sTmp+='MIN\t'
                                else:
                                        sTmp+='MINIMAX\t'
                        else:
                                if self.__modelType==0:
                                        sTmp+='MAX\t'
                                else:
                                        sTmp+='MAXIMIN\t'
                        
                        if self.__isFixedCosts:
                                sTmp+='VarAndFixedCosts'
                        else:
                                sTmp+='VarCosts'
                        sTmp+='\n'
                        f.write(sTmp)   
                        
                        
                        if self.__minBlock!=None and self.__maxBlock!=None:
                                f.write( 'Blocking:\t%s\t%s\n' % ( self.__intToStr(self.__minBlock) , self.__intToStr(self.__maxBlock) ) )
                        
                        if self.__isCapCon or self.__isSupplyCon or self.__isDemandCon or self.__isSingleSourceCon:
                                sTmp='SubjectTo:'
                                if self.__isCapCon:
                                        sTmp += '\tCapacities'
                                if self.__isSupplyCon:
                                        sTmp += '\tSupplyRanges'
                                if self.__isDemandCon:
                                        sTmp += '\tDemandRanges'
                                if self.__isSingleSourceCon:
                                        sTmp +='\tSingleSource'
                                sTmp+='\n'
                                f.write(sTmp)
                                        
                              
                        if self.__model.solverStatus == SOLVER_OK:
                                
                                f.write('Status:\t%s\n'% ( self.__model.solution.status))
                                
                                minCosts=bigM
                                maxCosts=0
                                totalFlow=0
                                sTmp=''
                               
                                sTmp='FLOWS:\n'
                                sTmp+='%-6s\t%-15s\t%-6s\t%-15s\t%15s\t%15s\t%15s\t%15s\t%15s\n' % ('From','Source','to','Destination','CostRate','Capacity','Flow','VariableCosts','FixedCosts')
                                
                                totalCosts=0
                                

                                for i,j in self.__edges:
                                               
                                        try:
                                                flow=0
                                                if self.__isSingleSourceCon:
                                                        flow = self.__model.y[(i,j)].activity * self.__destinations[j-1].demand
                                                else:
                                                        flow = self.__model.x[(i,j)].activity 

                                                if round(flow) > 0:
                                                                                                                        
                                                        if self.__costs[i-1][j-1]>maxCosts:
                                                                maxCosts=self.__costs[i-1][j-1]
                                                        if self.__costs[i-1][j-1]<minCosts:
                                                                minCosts=self.__costs[i-1][j-1]
                                                                        
                                                        totalFlow+=flow
                                                                
                                                        self.__sources[i-1].incFlow(flow)
                                                        self.__destinations[j-1].incFlow(flow)
                                                                
                                                        vcTmp=flow*self.__costs[i-1][j-1]
                                                        fcTmp=0
                                                        if self.__isFixedCosts:
                                                                fcTmp = self.__fixCosts[i-1][j-1]
                                                                        
                                                        totalCosts+=vcTmp+fcTmp
                                                                                                                        
                                                                                                                                        
                                                        sTmp+='%-6g\t%-15s\t%-6g\t%-15s\t%15s\t%15s\t%15s\t%15s\t%15s\n' % (i,self.__sources[i-1].name,j, self.__destinations[j-1].name, \
                                                                                                                                self.__floatToStr(self.__costs[i-1][j-1]),\
                                                                                                                                self.__intToStrM(self.__caps[i-1][j-1]),\
                                                                                                                                self.__intToStr(flow),\
                                                                                                                                self.__floatToStr(vcTmp),\
                                                                                                                                self.__floatToStr(fcTmp))
                                                                
                                        except Exception as err:
                                                raise TppException("Can't write SOL File <" + self.__solFile +">  <" +str( err)+">" )
                                                #pass
                                
                            
                                #f.write('TotalCosts:\t%20s\n' % self.__floatToStr(totalCosts ))
                                f.write('TotalCosts:\t%20.2f\n' % totalCosts )
                                
                                f.write('MinMaxCostRate:\t%s\t%s\n' % (self.__floatToStrM(minCosts),self.__floatToStrM(maxCosts)))
                                f.write('TotalFlow:\t%20.0f\n' % totalFlow )
                                f.write(sTmp)
                                
                                sTmp='SOURCES:\n'
                                sTmp+='%-4s\t%-15s\t%15s\t%15s\t%15s\t%15s\n' % ('Nr','Source','Flow','Supply','MinSupply','MaxSupply')
                                f.write(sTmp)
                                for i in range(1,self.__srcIdx+1):
                                        f.write( '%-4g\t%-15s\t%15s\t%15s\t%15s\t%15s\n' %      (i,self.__sources[i-1].name, \
                                                                                                self.__intToStr(self.__sources[i-1].flow),\
                                                                                                self.__intToStr(self.__sources[i-1].supply),\
                                                                                                self.__intToStr(self.__sources[i-1].minSupply),\
                                                                                                self.__sources[i-1].maxSupplyString ))
                                sTmp='DESTINATIONS:\n'
                                sTmp+='%-4s\t%-15s\t%15s\t%15s\t%15s\t%15s\n' % ('Nr','Destination','Flow','Demand','MinDemand','MaxDemand')
                                f.write(sTmp)
                                for j in range(1,self.__destIdx+1) :
                                        f.write( '%-4g\t%-15s\t%15s\t%15s\t%15s\t%15s\n' %      (j,self.__destinations[j-1].name, \
                                                                                                self.__intToStr(self.__destinations[j-1].flow),\
                                                                                                self.__intToStr(self.__destinations[j-1].demand),\
                                                                                                self.__intToStr(self.__destinations[j-1].minDemand),\
                                                                                                self.__destinations[j-1].maxDemandString ))
                                
                                
                        else:
                                f.write('Status:\t%s\n'% ( self.__model.solverMessage))
                        
                        f.write("EEE")
                                                
                        f.close()
                        
                except IOError as e:
                        raise TppException("Can't write SOL File <" + self.__solFile +">  <" +str( e)+">" )
        
        #*************** end __writeSolFile  *********************************************
        
                
#************** end CmplWLP  **********************************************





        