Module coinor.cuppy.genericSeparation

Invcollection

attributes: prob: Original problem type: LpProblem iter: Iteration number type: int x0: point given type: dict var: dictionary of the variables of prob type: dictionary dim: dimension of the problem type: int c: objective function coefficients of the prob type: dict invProb: inverse of the prob type: LpProblem currentXtremePoint: current extreme point generated type: dict dCurrent: InvProblem variable d in current iteration type: dict dPrevious: InvProblem variable d in previous iteration type: dict methods: init(self,prob,x0): creates invProb, and sets some attributes, prob and x0 are as described above generate_inverse(): generates invProb from prob and point x0 generate_xtreme_point(): generates extreme point for the current setting add_inequality(): creates inequality from current extreme point and adds it the to InvProb solve(): uses other methods iteratively to solve the InvProb

Expand source code
# inverse2.py This file contains classes to solve inverse optimization problems 
# it only utilizes pulp, no dippy
# -----------------------------------------------------------------------------

'''
InvCollection:
    attributes:
        prob:        Original problem
                     type: LpProblem
        iter:        Iteration number
                     type: int
        x0:          point given
                     type: dict
        var:         dictionary of the variables of prob
                     type: dictionary
        dim:         dimension of the problem
                     type: int
        c:           objective function coefficients of the prob
                     type: dict
        invProb:     inverse of the prob
                     type: LpProblem
        currentXtremePoint:
                     current extreme point generated
                     type: dict
        dCurrent:    InvProblem variable d in current iteration
                     type: dict
        dPrevious:   InvProblem variable d in previous iteration
                     type: dict
    methods:
        __init__(self,prob,x0):
                     creates invProb, and sets some attributes, prob and x0
                     are as described above
        generate_inverse():
                     generates invProb from prob and point x0
        generate_xtreme_point():
                     generates extreme point for the current setting
        add_inequality():
                     creates inequality from current extreme point and adds
                     it the to InvProb
        solve():     uses other methods iteratively to solve the InvProb
'''
from __future__ import print_function
from __future__ import absolute_import
from builtins import str
from builtins import range
from builtins import object

__version__    = '0.5.2'
__author__     = 'Aykut Bulut and Ted Ralphs'
__license__    = 'Eclipse Public License'
__maintainer__ = 'Ted Ralphs'
__email__      = '[email protected]'
__url__        = 'https://github.com/tkralphs/CuPPy'

import importlib as ilib
from copy import deepcopy
from pulp import LpProblem, LpVariable, LpMinimize, LpInteger
from pulp import LpContinuous, lpSum, LpConstraintVar, LpStatus
try:
    from src.grumpy.polyhedron2D import Polyhedron2D, Figure
except ImportError:
    from coinor.grumpy.polyhedron2D import Polyhedron2D, Figure
from .milpInstance import MILPInstance
import sys
sys.path.append('examples')


EPS = 1e-6
class GenericSeparation(object):

    def __init__(self, origProb, x0, pi_init = None):
        if pi_init == None:
            pi_init = [(v.name, 0) for v in list(self.var.values())]
        self.prob = origProb
        self.iter = 1
        self.x0 = x0
        self.var = origProb.variablesDict()
        self.dim = len(self.var)
        self.currentXtremePoint = {}
        self.solver = None
        self.c = dict(list((v.name,c) for v,c in origProb.objective.items()))
        for v in self.var:
            if v in self.c:
                continue
            else:
                self.c[v] = 0.0
        self.generate_separation_problem()
        self.piCurrent = dict([(v.name, pi_init[v.name]) for v in list(self.var.values())]) 
        self.piPrevious = dict([(v.name, 0) for v in list(self.var.values())]) 
        self.extremePoints = []
        self.f = Figure()
        
    def generate_separation_problem(self):
        self.sepProb = LpProblem (name='separation '+self.prob.name, sense=LpMinimize)
        self.pi = dict(list((v,LpVariable('pi'+v, None, None, LpContinuous,
                                         None))
                                         for v in self.var)) 
        self.sepProb += lpSum(self.pi[v]*self.x0[v] for v in self.var)

    def generate_xtreme_point(self):
        obj = LpConstraintVar()
        for v in self.prob.variables():
            obj.addVariable(v, self.piCurrent[v.name])
        self.prob.setObjective(obj)
        self.prob.solve()
        #solvers.COIN_CMD.solve(self.prob)
        for v in self.var:
            self.currentXtremePoint[v] = self.var[v].value()
        if self.output == 1:
            currentXtremePointList = list(self.currentXtremePoint.items())
            currentXtremePointList.sort()
            for v in currentXtremePointList:
                print(v[0]+'\t', v[1])
        self.extremePoints.append(list(self.currentXtremePoint.values()))
        return self.prob.objective.value()

    def add_inequality(self):
        # change this, you should not access sense directly call a method
        self.sepProb += lpSum (self.currentXtremePoint[v]*self.pi[v] for v in self.var) >= 1

    def separate(self, output = False, p = None):
        self.output = output
        while True:
            print('Iteration ', self.iter)
            if self.generate_xtreme_point() >= 1-EPS:
                break
            self.add_inequality()
            if self.output:
                print("Separation problem solution status:", LpStatus[self.sepProb.solve()])
                for v in self.var:
                    if self.pi[v].value() is not None:
                        print(self.pi[v].name+'\t\t', self.pi[v].value())
                    else:
                        print(self.pi[v].name+'\t\t', 0)
            self.piPrevious = deepcopy(self.piCurrent)
            for v in self.var:
                if self.pi[v].value() is not None:
                    self.piCurrent[v] = self.pi[v].value()
                else:
                    self.piCurrent[v] = 0
            self.iter += 1
            if p is not None:
                self.f.initialize()
                self.f.add_polyhedron(p, label = 'Polyhedron P')
                xList = (list(self.x0.values())[0], list(self.x0.values())[1])
                if len(self.extremePoints) > 2:
                    pp = Polyhedron2D(points = self.extremePoints)
                    self.f.add_polyhedron(pp, color = 'red', linestyle = 'dashed',
                                          label = 'Convex Hull of Generated Points')
                elif len(self.extremePoints) == 1:
                    self.f.add_point(self.extremePoints[0], radius = 0.05, 
                                     color = 'green')
                    self.f.add_text([self.extremePoints[0][0]-0.5, 
                                    self.extremePoints[0][1]-0.08], '$x^0$')
                else:
                    self.f.add_line_segment(self.extremePoints[0], 
                                            self.extremePoints[1], 
                                            color = 'red',
                                            linestyle = 'dashed',
                                            label = 'Convex Hull of Generated Points')
                self.f.set_xlim(p.xlim)
                self.f.set_ylim(p.ylim)
                self.f.add_point(xList, radius = 0.05, color = 'red')
                self.f.add_text([xList[0]-0.5, xList[1]-0.08], '$x^*$')
                dList = (list(self.piCurrent.values())[0], list(self.piCurrent.values())[1])
                self.f.add_line(dList, 1, 
                                p.xlim, p.ylim, color = 'green', 
                                linestyle = 'dashed', label = 'Separating Hyperplane')
                self.f.show()
            if self.output:
                print(self.sepProb.objective.value())            

def read_instance(module_name):
    '''
    creates problem defined in the documentation of this file
    ''' 
    mip = ilib.import_module(module_name)
            
    # create LpProblem instance
    prob = LpProblem("MIP", LpMinimize)
    # create variables
    x = []
    for i in range(len(mip.A[0])):
        x.append(LpVariable('x_'+str(i), 0, None, LpInteger))
    # add obj function
    prob +=  lpSum(mip.c[i]*x[i] for i in range(len(mip.A[0])))
    # add constraints to the prob
    for i in range(len(mip.A)):
        prob +=  mip.A[i][0]*x[0] + mip.A[i][1]*x[1] <= mip.b[i]
    return prob, x, mip

if __name__ == '__main__':
    
    display = True
    prob, vars, mip = read_instance(module_name = 'MIP8')

    if display:
        p = Polyhedron2D(A = mip.A, b = mip.b)
        f = Figure()
        f.add_polyhedron(p, show_int_points = True, label = 'Polyhedron P')
        f.set_xlim(p.xlim)
        f.set_ylim(p.ylim)
        f.add_point(mip.x_sep, radius = 0.05, color = 'red')
        f.add_text([mip.x_sep[0]-0.5, mip.x_sep[1]-0.08], '$x^*$')
        f.show()

    # This is the point to be separated 
    x0 = {}
    for index, value in enumerate(mip.x_sep):
        x0[vars[index].name] = value
    i = 0
    ic = GenericSeparation(prob, x0, {'x_0': -1, 'x_1' : 0})
    ic.separate(output = True, p = p)
    print('separation problem objective value', ic.sepProb.objective.value())

Functions

def read_instance(module_name)

creates problem defined in the documentation of this file

Expand source code
def read_instance(module_name):
    '''
    creates problem defined in the documentation of this file
    ''' 
    mip = ilib.import_module(module_name)
            
    # create LpProblem instance
    prob = LpProblem("MIP", LpMinimize)
    # create variables
    x = []
    for i in range(len(mip.A[0])):
        x.append(LpVariable('x_'+str(i), 0, None, LpInteger))
    # add obj function
    prob +=  lpSum(mip.c[i]*x[i] for i in range(len(mip.A[0])))
    # add constraints to the prob
    for i in range(len(mip.A)):
        prob +=  mip.A[i][0]*x[0] + mip.A[i][1]*x[1] <= mip.b[i]
    return prob, x, mip

Classes

class GenericSeparation (origProb, x0, pi_init=None)
Expand source code
class GenericSeparation(object):

    def __init__(self, origProb, x0, pi_init = None):
        if pi_init == None:
            pi_init = [(v.name, 0) for v in list(self.var.values())]
        self.prob = origProb
        self.iter = 1
        self.x0 = x0
        self.var = origProb.variablesDict()
        self.dim = len(self.var)
        self.currentXtremePoint = {}
        self.solver = None
        self.c = dict(list((v.name,c) for v,c in origProb.objective.items()))
        for v in self.var:
            if v in self.c:
                continue
            else:
                self.c[v] = 0.0
        self.generate_separation_problem()
        self.piCurrent = dict([(v.name, pi_init[v.name]) for v in list(self.var.values())]) 
        self.piPrevious = dict([(v.name, 0) for v in list(self.var.values())]) 
        self.extremePoints = []
        self.f = Figure()
        
    def generate_separation_problem(self):
        self.sepProb = LpProblem (name='separation '+self.prob.name, sense=LpMinimize)
        self.pi = dict(list((v,LpVariable('pi'+v, None, None, LpContinuous,
                                         None))
                                         for v in self.var)) 
        self.sepProb += lpSum(self.pi[v]*self.x0[v] for v in self.var)

    def generate_xtreme_point(self):
        obj = LpConstraintVar()
        for v in self.prob.variables():
            obj.addVariable(v, self.piCurrent[v.name])
        self.prob.setObjective(obj)
        self.prob.solve()
        #solvers.COIN_CMD.solve(self.prob)
        for v in self.var:
            self.currentXtremePoint[v] = self.var[v].value()
        if self.output == 1:
            currentXtremePointList = list(self.currentXtremePoint.items())
            currentXtremePointList.sort()
            for v in currentXtremePointList:
                print(v[0]+'\t', v[1])
        self.extremePoints.append(list(self.currentXtremePoint.values()))
        return self.prob.objective.value()

    def add_inequality(self):
        # change this, you should not access sense directly call a method
        self.sepProb += lpSum (self.currentXtremePoint[v]*self.pi[v] for v in self.var) >= 1

    def separate(self, output = False, p = None):
        self.output = output
        while True:
            print('Iteration ', self.iter)
            if self.generate_xtreme_point() >= 1-EPS:
                break
            self.add_inequality()
            if self.output:
                print("Separation problem solution status:", LpStatus[self.sepProb.solve()])
                for v in self.var:
                    if self.pi[v].value() is not None:
                        print(self.pi[v].name+'\t\t', self.pi[v].value())
                    else:
                        print(self.pi[v].name+'\t\t', 0)
            self.piPrevious = deepcopy(self.piCurrent)
            for v in self.var:
                if self.pi[v].value() is not None:
                    self.piCurrent[v] = self.pi[v].value()
                else:
                    self.piCurrent[v] = 0
            self.iter += 1
            if p is not None:
                self.f.initialize()
                self.f.add_polyhedron(p, label = 'Polyhedron P')
                xList = (list(self.x0.values())[0], list(self.x0.values())[1])
                if len(self.extremePoints) > 2:
                    pp = Polyhedron2D(points = self.extremePoints)
                    self.f.add_polyhedron(pp, color = 'red', linestyle = 'dashed',
                                          label = 'Convex Hull of Generated Points')
                elif len(self.extremePoints) == 1:
                    self.f.add_point(self.extremePoints[0], radius = 0.05, 
                                     color = 'green')
                    self.f.add_text([self.extremePoints[0][0]-0.5, 
                                    self.extremePoints[0][1]-0.08], '$x^0$')
                else:
                    self.f.add_line_segment(self.extremePoints[0], 
                                            self.extremePoints[1], 
                                            color = 'red',
                                            linestyle = 'dashed',
                                            label = 'Convex Hull of Generated Points')
                self.f.set_xlim(p.xlim)
                self.f.set_ylim(p.ylim)
                self.f.add_point(xList, radius = 0.05, color = 'red')
                self.f.add_text([xList[0]-0.5, xList[1]-0.08], '$x^*$')
                dList = (list(self.piCurrent.values())[0], list(self.piCurrent.values())[1])
                self.f.add_line(dList, 1, 
                                p.xlim, p.ylim, color = 'green', 
                                linestyle = 'dashed', label = 'Separating Hyperplane')
                self.f.show()
            if self.output:
                print(self.sepProb.objective.value())            

Methods

def add_inequality(self)
Expand source code
def add_inequality(self):
    # change this, you should not access sense directly call a method
    self.sepProb += lpSum (self.currentXtremePoint[v]*self.pi[v] for v in self.var) >= 1
def generate_separation_problem(self)
Expand source code
def generate_separation_problem(self):
    self.sepProb = LpProblem (name='separation '+self.prob.name, sense=LpMinimize)
    self.pi = dict(list((v,LpVariable('pi'+v, None, None, LpContinuous,
                                     None))
                                     for v in self.var)) 
    self.sepProb += lpSum(self.pi[v]*self.x0[v] for v in self.var)
def generate_xtreme_point(self)
Expand source code
def generate_xtreme_point(self):
    obj = LpConstraintVar()
    for v in self.prob.variables():
        obj.addVariable(v, self.piCurrent[v.name])
    self.prob.setObjective(obj)
    self.prob.solve()
    #solvers.COIN_CMD.solve(self.prob)
    for v in self.var:
        self.currentXtremePoint[v] = self.var[v].value()
    if self.output == 1:
        currentXtremePointList = list(self.currentXtremePoint.items())
        currentXtremePointList.sort()
        for v in currentXtremePointList:
            print(v[0]+'\t', v[1])
    self.extremePoints.append(list(self.currentXtremePoint.values()))
    return self.prob.objective.value()
def separate(self, output=False, p=None)
Expand source code
def separate(self, output = False, p = None):
    self.output = output
    while True:
        print('Iteration ', self.iter)
        if self.generate_xtreme_point() >= 1-EPS:
            break
        self.add_inequality()
        if self.output:
            print("Separation problem solution status:", LpStatus[self.sepProb.solve()])
            for v in self.var:
                if self.pi[v].value() is not None:
                    print(self.pi[v].name+'\t\t', self.pi[v].value())
                else:
                    print(self.pi[v].name+'\t\t', 0)
        self.piPrevious = deepcopy(self.piCurrent)
        for v in self.var:
            if self.pi[v].value() is not None:
                self.piCurrent[v] = self.pi[v].value()
            else:
                self.piCurrent[v] = 0
        self.iter += 1
        if p is not None:
            self.f.initialize()
            self.f.add_polyhedron(p, label = 'Polyhedron P')
            xList = (list(self.x0.values())[0], list(self.x0.values())[1])
            if len(self.extremePoints) > 2:
                pp = Polyhedron2D(points = self.extremePoints)
                self.f.add_polyhedron(pp, color = 'red', linestyle = 'dashed',
                                      label = 'Convex Hull of Generated Points')
            elif len(self.extremePoints) == 1:
                self.f.add_point(self.extremePoints[0], radius = 0.05, 
                                 color = 'green')
                self.f.add_text([self.extremePoints[0][0]-0.5, 
                                self.extremePoints[0][1]-0.08], '$x^0$')
            else:
                self.f.add_line_segment(self.extremePoints[0], 
                                        self.extremePoints[1], 
                                        color = 'red',
                                        linestyle = 'dashed',
                                        label = 'Convex Hull of Generated Points')
            self.f.set_xlim(p.xlim)
            self.f.set_ylim(p.ylim)
            self.f.add_point(xList, radius = 0.05, color = 'red')
            self.f.add_text([xList[0]-0.5, xList[1]-0.08], '$x^*$')
            dList = (list(self.piCurrent.values())[0], list(self.piCurrent.values())[1])
            self.f.add_line(dList, 1, 
                            p.xlim, p.ylim, color = 'green', 
                            linestyle = 'dashed', label = 'Separating Hyperplane')
            self.f.show()
        if self.output:
            print(self.sepProb.objective.value())