Example #1
0
    def __init__(self,l,u,fs,
                 A=None,b=None,C=None,d=None,constr=None,variable=None,
                 tol=.01,sub_tol=None,name='',nthreads = 1,check_z=False,
                 solver = 'glpk'):
        
        # parameters
        self.tol = tol
        if sub_tol:
            self.sub_tol = sub_tol
        else:
            self.sub_tol = tol
        if name: 
            self.name = name
        else:
            self.name = 'sp'
        self.nthreads = nthreads
        self.solver = solver
        
        # box constraints
        # cast everything to float, since cvxopt breaks if numpy.float64 floats are used
        self.l = [float(li) for li in l]
        self.u = [float(ui) for ui in u]
        
        self.fs = fs
                
        # check dimensions and adequacy of data
        if not (len(fs)==len(l) and len(fs)==len(u)):
            raise ValueError('Check problem dimensions')
        for i,f in enumerate(self.fs):
            if len(f)<3:    
                self.fs[i] = utilities.find_z(f,l[i],u[i],self.sub_tol)
        self.check_z = check_z

        utilities.get_constraints(self,A,b,C,d,constr,variable,n=len(l),format=solver)
            
        # initialize        
        self.x = self.u
        self.best_node = Node(l,u,self)
        self.LB = self.best_node.LB
        self._bounds = Queue()
        self.bounds = []
        
        # sort nodes for splitting in descending order by upper bound
        self.partition = MaxQueue()
        self.partition.put((self.best_node.UB,self.best_node))
Example #2
0
File: bb.py Project: sl7rf/sigopt
    def __init__(self,
                 l,
                 u,
                 fs,
                 A=None,
                 b=None,
                 C=None,
                 d=None,
                 constr=None,
                 variable=None,
                 tol=.01,
                 sub_tol=None,
                 name='',
                 nthreads=1,
                 check_z=False,
                 solver='glpk'):

        # parameters
        self.tol = tol
        if sub_tol:
            self.sub_tol = sub_tol
        else:
            self.sub_tol = tol
        if name:
            self.name = name
        else:
            self.name = 'sp'
        self.nthreads = nthreads
        self.solver = solver

        # box constraints
        # cast everything to float, since cvxopt breaks if numpy.float64 floats are used
        self.l = [float(li) for li in l]
        self.u = [float(ui) for ui in u]

        self.fs = fs

        # check dimensions and adequacy of data
        if not (len(fs) == len(l) and len(fs) == len(u)):
            raise ValueError('Check problem dimensions')
        for i, f in enumerate(self.fs):
            if len(f) < 3:
                self.fs[i] = utilities.find_z(f, l[i], u[i], self.sub_tol)
        self.check_z = check_z

        utilities.get_constraints(self,
                                  A,
                                  b,
                                  C,
                                  d,
                                  constr,
                                  variable,
                                  n=len(l),
                                  format=solver)

        # initialize
        self.x = self.u
        self.best_node = Node(l, u, self)
        self.LB = self.best_node.LB
        self._bounds = Queue()
        self.bounds = []

        # sort nodes for splitting in descending order by upper bound
        self.partition = MaxQueue()
        self.partition.put((self.best_node.UB, self.best_node))
Example #3
0
class Problem(object):
    '''Container for problem parameters
    
    Represents the problem
    
              maximize sum(f_i(x_i)) 
              subject to:
                       A*x <= b
                       Cx == d
                       l <= x <= u
                       constr
                       
    where each fuction f_i is sigmoidal.
    
    Solves the problem using a branch and bound solver to specified accuracy
    
    Arguments:
        l       :  a list of upper bounds on variable x
        u       :  a list of lower bounds on variable x
        fs      :  a list of tuples (f,fprime,z) where fprime gives the derivative of f.
                   f should be convex for x<z and concave for x>z 
        A       :  an arbitrary matrix (n x m)
        b       :  an arbitrary vector (m x 1)
        tol     :  the accuracy required for the problem
        sub_tol :  the accuracy with which to compute the concave envelopes
    
    problem.solve(maxiters) runs the branch and bound solver 
        until a solution of accuracy self.tol is reached, or until
        maxiters concave subproblems have been solved.
    
    problem.best_node is the best node found so far 
        (the one with the highest lower bound) at any time.
        
    problem.LB is the best lower bound on the optimal value found so far; 
        it is achieved by problem.best_node.x
    
    problem.partition is a priority queue containing all nodes under consideration
        indexed by their upper bounds, in decreasing order.
        
    problem.bounds is a list of the bounds obtained after each iteration.  
    '''
    
    def __init__(self,l,u,fs,
                 A=None,b=None,C=None,d=None,constr=None,variable=None,
                 tol=.01,sub_tol=None,name='',nthreads = 1,check_z=False,
                 solver = 'glpk'):
        
        # parameters
        self.tol = tol
        if sub_tol:
            self.sub_tol = sub_tol
        else:
            self.sub_tol = tol
        if name: 
            self.name = name
        else:
            self.name = 'sp'
        self.nthreads = nthreads
        self.solver = solver
        
        # box constraints
        # cast everything to float, since cvxopt breaks if numpy.float64 floats are used
        self.l = [float(li) for li in l]
        self.u = [float(ui) for ui in u]
        
        self.fs = fs
                
        # check dimensions and adequacy of data
        if not (len(fs)==len(l) and len(fs)==len(u)):
            raise ValueError('Check problem dimensions')
        for i,f in enumerate(self.fs):
            if len(f)<3:    
                self.fs[i] = utilities.find_z(f,l[i],u[i],self.sub_tol)
        self.check_z = check_z

        utilities.get_constraints(self,A,b,C,d,constr,variable,n=len(l),format=solver)
            
        # initialize        
        self.x = self.u
        self.best_node = Node(l,u,self)
        self.LB = self.best_node.LB
        self._bounds = Queue()
        self.bounds = []
        
        # sort nodes for splitting in descending order by upper bound
        self.partition = MaxQueue()
        self.partition.put((self.best_node.UB,self.best_node))
    
    def run_serial(self,maxiters=0,verbose=False,prune=False,tol=None):
        '''
        Finds a solution of quality problem.tol to the problem.
        
        The optimal node found at any point (ie, the one with the best lower bound 
        and an x that achieves it) is stored in problem.best_node.
        
        The algorithm works by popping the node with the highest upper bound off of the 
        partition, splitting it, and computing bounds for the resulting subrectangles.
        The subrectangles are then inserted into the problem.partition.
        
        The algorithm terminates when the stopping criterion is met, 
        ie when the highest upper bound is less than problem.tol
        greater than the highest lower bound,
        or after maxiters subproblems have been solved.
        '''
        if tol is None: tol = self.tol
        iter = 0
        while not maxiters or iter < maxiters:
            iter += 1
            UB, node = self.partition.get_nowait()
        
            # record bounds
            self._bounds.put((self.LB,UB))
            if verbose: 
                print 'Bounds',self.LB,UB,'found by',self.name
                
            # stopping criterion
            if UB - self.LB < tol: 
              # a tolerable solution has been found!
              # put current node back in the partition
              if verbose: print 'Stopping criterion reached by %s' % (self.name)
              self.partition.put((UB,node))
              break
            if UB == -float("inf"):
              if verbose: print 'Problem infeasible'
              break
        
            # keep going
            for child in node.split(self):
                if verbose: 
                    print 'split into child with bounds',child.LB,child.UB
                if child.LB > self.LB:
                    if verbose: 
                        print 'Node with best lower bound %.4f found' \
                               % (child.LB)
                    self.LB = child.LB
                    self.best_node = child
                # only put child into partition if child is active
                if prune is False or child.UB >= self.LB:
                    self.partition.put((child.UB,child))
                else:
                    if verbose:
                        print 'Discarded node with bounds',child.LB,child.UB,'since LB is',self.LB
        self._get_bounds()
        self.x = self.best_node.x
        
    def solve(self,*args,**kwargs):
        '''
        Convenience wrapper around run_serial
        '''
        self.run_serial(*args,**kwargs)
        
    def _get_bounds(self):
        while not self._bounds.empty():
            next = self._bounds.get()
            self.bounds.append(next)
        return self.bounds
Example #4
0
File: bb.py Project: sl7rf/sigopt
class Problem(object):
    '''Container for problem parameters
    
    Represents the problem
    
              maximize sum(f_i(x_i)) 
              subject to:
                       A*x <= b
                       Cx == d
                       l <= x <= u
                       constr
                       
    where each fuction f_i is sigmoidal.
    
    Solves the problem using a branch and bound solver to specified accuracy
    
    Arguments:
        l       :  a list of upper bounds on variable x
        u       :  a list of lower bounds on variable x
        fs      :  a list of tuples (f,fprime,z) where fprime gives the derivative of f.
                   f should be convex for x<z and concave for x>z 
        A       :  an arbitrary matrix (n x m)
        b       :  an arbitrary vector (m x 1)
        tol     :  the accuracy required for the problem
        sub_tol :  the accuracy with which to compute the concave envelopes
    
    problem.solve(maxiters) runs the branch and bound solver 
        until a solution of accuracy self.tol is reached, or until
        maxiters concave subproblems have been solved.
    
    problem.best_node is the best node found so far 
        (the one with the highest lower bound) at any time.
        
    problem.LB is the best lower bound on the optimal value found so far; 
        it is achieved by problem.best_node.x
    
    problem.partition is a priority queue containing all nodes under consideration
        indexed by their upper bounds, in decreasing order.
        
    problem.bounds is a list of the bounds obtained after each iteration.
    '''
    def __init__(self,
                 l,
                 u,
                 fs,
                 A=None,
                 b=None,
                 C=None,
                 d=None,
                 constr=None,
                 variable=None,
                 tol=.01,
                 sub_tol=None,
                 name='',
                 nthreads=1,
                 check_z=False,
                 solver='glpk'):

        # parameters
        self.tol = tol
        if sub_tol:
            self.sub_tol = sub_tol
        else:
            self.sub_tol = tol
        if name:
            self.name = name
        else:
            self.name = 'sp'
        self.nthreads = nthreads
        self.solver = solver

        # box constraints
        # cast everything to float, since cvxopt breaks if numpy.float64 floats are used
        self.l = [float(li) for li in l]
        self.u = [float(ui) for ui in u]

        self.fs = fs

        # check dimensions and adequacy of data
        if not (len(fs) == len(l) and len(fs) == len(u)):
            raise ValueError('Check problem dimensions')
        for i, f in enumerate(self.fs):
            if len(f) < 3:
                self.fs[i] = utilities.find_z(f, l[i], u[i], self.sub_tol)
        self.check_z = check_z

        utilities.get_constraints(self,
                                  A,
                                  b,
                                  C,
                                  d,
                                  constr,
                                  variable,
                                  n=len(l),
                                  format=solver)

        # initialize
        self.x = self.u
        self.best_node = Node(l, u, self)
        self.LB = self.best_node.LB
        self._bounds = Queue()
        self.bounds = []

        # sort nodes for splitting in descending order by upper bound
        self.partition = MaxQueue()
        self.partition.put((self.best_node.UB, self.best_node))

    def run_serial(self, maxiters=0, verbose=False, prune=False, tol=None):
        '''
        Finds a solution of quality problem.tol to the problem.
        
        The optimal node found at any point (ie, the one with the best lower bound 
        and an x that achieves it) is stored in problem.best_node.
        
        The algorithm works by popping the node with the highest upper bound off of the 
        partition, splitting it, and computing bounds for the resulting subrectangles.
        The subrectangles are then inserted into the problem.partition.
        
        The algorithm terminates when the stopping criterion is met, 
        ie when the highest upper bound is less than problem.tol
        greater than the highest lower bound,
        or after maxiters subproblems have been solved.
        '''
        if tol is None: tol = self.tol
        iter = 0
        while not maxiters or iter < maxiters:
            iter += 1
            UB, node = self.partition.get_nowait()

            # record bounds
            self._bounds.put((self.LB, UB))
            if verbose:
                print 'Bounds', self.LB, UB, 'found by', self.name

            # stopping criterion
            if UB - self.LB < tol:
                # a tolerable solution has been found!
                # put current node back in the partition
                if verbose:
                    print 'Stopping criterion reached by %s' % (self.name)
                self.partition.put((UB, node))
                break
            if UB == -float("inf"):
                if verbose: print 'Problem infeasible'
                break

            # keep going
            for child in node.split(self):
                if verbose:
                    print 'split into child with bounds', child.LB, child.UB
                if child.LB > self.LB:
                    if verbose:
                        print 'Node with best lower bound %.4f found' \
                               % (child.LB)
                    self.LB = child.LB
                    self.best_node = child
                # only put child into partition if child is active
                if prune is False or child.UB >= self.LB:
                    self.partition.put((child.UB, child))
                else:
                    if verbose:
                        print 'Discarded node with bounds', child.LB, child.UB, 'since LB is', self.LB
        self._get_bounds()
        self.x = self.best_node.x

    def solve(self, *args, **kwargs):
        '''
        Convenience wrapper around run_serial
        '''
        self.run_serial(*args, **kwargs)

    def _get_bounds(self):
        while not self._bounds.empty():
            next = self._bounds.get()
            self.bounds.append(next)
        return self.bounds