Changeset 5795


Ignore:
Timestamp:
05/20/12 19:53:55 (2 years ago)
Author:
wehart
Message:

Migrating model xform stuff out of PyomoModel?.py

Location:
coopr.pyomo/trunk/coopr/pyomo
Files:
1 added
1 edited

Legend:

Unmodified
Added
Removed
  • coopr.pyomo/trunk/coopr/pyomo/base/PyomoModel.py

    r5794 r5795  
    118118        process = kwargs.pop('process', None) 
    119119        if process is None: 
    120             return coopr.core.CooprAPIFactory(self._create)({}, model=self, **kwargs).instance 
     120            data = coopr.core.CooprAPIFactory(self._create)({}, model=self, **kwargs) 
    121121        else: 
    122             return coopr.core.CooprAPIFactory(process)({}, model=self, **kwargs).instance 
     122            data = coopr.core.CooprAPIFactory(process)({}, model=self, **kwargs) 
     123        return data.instance 
    123124 
    124125    def clone(self): 
    125126        """Create a copy of this model""" 
     127        # TODO: check that this works recursively for nested models 
    126128        self._model = None 
    127129        for block in self.all_blocks(): 
     
    180182    def reset(self): 
    181183        # TODO: check that this works recursively for nested models 
    182          
    183184        for name in self.components: 
    184185            self.components[name].reset() 
     
    192193            self = Model.preprocessor_ep.service(item).preprocess(self) 
    193194 
    194     def solution(selfNone): 
     195    def Xsolution(selfNone): 
    195196        """Return the solution""" 
    196197        soln = [] 
     
    260261                else: 
    261262                    tmp[(var_value.component().name,var_value.index)] = (var_value.name, entry) 
    262                 #vars[var_value.name] = entry 
    263263            for key in sorted(tmp.keys()): 
    264264                value = tmp[key] 
     
    325325             allow_consistent_values_for_fixed_vars=False, 
    326326             profile_memory=0, ignore_invalid_labels=False): 
    327         """ Load the model with data from a file or a Solution object """ 
     327        """ 
     328        Load the model with data from a file or a Solution object 
     329        """ 
    328330        if arg is None or type(arg) is str: 
    329331            self._load_model_data(ModelData(filename=arg,model=self), namespaces, profile_memory=profile_memory) 
     
    367369                ignore_invalid_labels=ignore_invalid_labels ) 
    368370            return True 
    369         #elif type(arg) in (tuple, list): 
    370         #    self._load_solution( 
    371         #        arg, 
    372         #        allow_consistent_values_for_fixed_vars 
    373         #        = allow_consistent_values_for_fixed_vars, 
    374         #        ignore_invalid_labels=ignore_invalid_labels ) 
    375         #    return True 
    376371        else: 
    377372            msg = "Cannot load model with object of type '%s'" 
    378373            raise ValueError, msg % str( type(arg) ) 
    379374 
    380     def store_info(self, results): 
    381         """ Store model information into a SolverResults object """ 
     375    def Xstore_info(self, results): 
     376        """ 
     377        Store model information into a SolverResults object 
     378        """ 
    382379        results.problem.name = self.name 
    383380 
     
    410407        Load declarations from a ModelData object. 
    411408        """ 
    412  
     409        # 
    413410        # As we are primarily generating objects here (and acyclic ones 
    414411        # at that), there is no need to run the GC until the entire 
    415412        # model is created.  Simple reference-counting should be 
    416413        # sufficient to keep memory use under control. 
     414        # 
    417415        suspend_gc = PauseGC() 
    418  
     416        # 
     417        # Unlike the standard method in the pympler summary module, the tracker 
     418        # doesn't print 0-byte entries to pad out the limit. 
     419        # 
    419420        profile_memory = kwds.get('profile_memory', 0) 
    420  
    421         # for pretty-printing summaries - unlike the standard 
    422         # method in the pympler summary module, the tracker 
    423         # doesn't print 0-byte entries to pad out the limit. 
    424421        if (pympler_available is True) and (profile_memory >= 2): 
    425422            memory_tracker = tracker.SummaryTracker() 
    426  
     423        # 
    427424        # Do some error checking 
     425        # 
    428426        for namespace in namespaces: 
    429427            if not namespace is None and not namespace in modeldata._data: 
    430428                msg = "Cannot access undefined namespace: '%s'" 
    431429                raise IOError, msg % namespace 
    432  
     430        # 
    433431        # Initialize each component in order. 
    434         components = [key for key in self.components] 
    435  
    436         for component_name in components: 
    437  
     432        # 
     433        for component_name in self.components: 
    438434            if (pympler_available is True) and (profile_memory >= 2): 
    439435                memory_tracker.create_summary() 
    440  
     436            # 
    441437            if self.components[component_name].type() is Model: 
    442438                continue 
     
    459455                            var.domain = IntegerSet() 
    460456                            var.domain.name = domain_name 
    461                             self.active_components(Var)[key] = var 
     457                            self.active_components(Var)[component_name] = var 
    462458 
    463459            declaration = self.components[component_name] 
     
    631627        """ 
    632628        Write the model to a file, with a given format. 
     629 
     630        TODO: verify that this method needs to return the filename and symbol_map. 
     631        TODO: these should be returned in a Bunch() object. 
    633632        """ 
    634633        if format is None and not filename is None: 
    635634            # 
    636             # Guess the format 
     635            # Guess the format if none is specified 
    637636            # 
    638637            format = guess_format(filename) 
    639         #print "X",str(format),coopr.opt.WriterFactory.services() 
     638        if solver_capability is None: 
     639            solver_capability = lambda x: True 
     640        # 
    640641        problem_writer = coopr.opt.WriterFactory(format) 
    641642        if problem_writer is None: 
    642             msg = "Cannot write model in format '%s': no model writer "      \ 
    643                   "registered for that format" 
    644             raise ValueError, msg % str(format) 
    645  
    646         if solver_capability is None: 
    647             solver_capability = lambda x: True 
     643            raise ValueError, \ 
     644                    "Cannot write model in format '%s': no model writer " \ 
     645                    "registered for that format" \ 
     646                    % str(format) 
     647        # 
    648648        (fname, symbol_map) = problem_writer(self, filename, solver_capability) 
     649        # 
    649650        if __debug__: 
    650651            if logger.isEnabledFor(logging.DEBUG): 
    651652                logger.debug("Writing model '%s' to file '%s' with format %s", self.name, str(fname), str(format)) 
    652653        return fname, symbol_map 
    653  
    654     def to_standard_form(self): 
    655         """ 
    656         Produces a standard-form representation of the model. Returns 
    657         the coefficient matrix (A), the cost vector (c), and the 
    658         constraint vector (b), where the 'standard form' problem is 
    659  
    660         min/max c'x 
    661         s.t.    Ax = b 
    662                 x >= 0 
    663  
    664         All three returned values are instances of the array.array 
    665         class, and store Python floats (C doubles). 
    666         """ 
    667  
    668         from coopr.pyomo.expr import generate_canonical_repn 
    669  
    670  
    671         # We first need to create an map of all variables to their column 
    672         # number 
    673         colID = {} 
    674         ID2name = {} 
    675         id = 0 
    676         tmp = self.variables().keys() 
    677         tmp.sort() 
    678  
    679         for v in tmp: 
    680             colID[v] = id 
    681             ID2name[id] = v 
    682             id += 1 
    683  
    684         # First we go through the constraints and introduce slack and excess 
    685         # variables to eliminate inequality constraints 
    686         # 
    687         # N.B. Structure heirarchy: 
    688         # 
    689         # active_components: {class: {attr_name: object}} 
    690         # object -> Constraint: ._data: {ndx: _ConstraintData} 
    691         # _ConstraintData: .lower, .body, .upper 
    692         # 
    693         # So, altogether, we access a lower bound via 
    694         # 
    695         # model.active_components()[Constraint]['con_name']['index'].lower 
    696         # 
    697         # {le,ge,eq}Constraints are 
    698         # {constraint_name: {index: {variable_or_none: coefficient}} objects 
    699         # that represent each constraint. None in the innermost dictionary 
    700         # represents the constant term. 
    701         # 
    702         # i.e. 
    703         # 
    704         # min  x1 + 2*x2 +          x4 
    705         # s.t. x1                         = 1 
    706         #           x2   + 3*x3          <= -1 
    707         #      x1 +                 x4   >= 3 
    708         #      x1 + 2*x2 +      +   3*x4 >= 0 
    709         # 
    710         # 
    711         # would be represented as (modulo the names of the variables, 
    712         # constraints, and indices) 
    713         # 
    714         # eqConstraints = {'c1': {None: {'x1':1, None:-1}}} 
    715         # leConstraints = {'c2': {None: {'x2':1, 'x3':3, None:1}}} 
    716         # geConstraints = {'c3': {None: {'x1':1, 'x4':1, None:-3}}, 
    717         #                  'c4': {None: {'x1':1, 'x2':2, 'x4':1, None:0}}} 
    718         # 
    719         # Note the we have the luxury of dealing only with linear terms. 
    720         var_id_map = {} 
    721         leConstraints = {} 
    722         geConstraints = {} 
    723         eqConstraints = {} 
    724         objectives = {} 
    725         # For each registered component 
    726         for c in self.active_components(): 
    727  
    728             # Get all subclasses of Constraint 
    729             if issubclass(c, Constraint): 
    730                 cons = self.active_components(c) 
    731  
    732                 # Get the name of the constraint, and the constraint set itself 
    733                 for con_set_name in cons: 
    734                     con_set = cons[con_set_name] 
    735  
    736                     # For each indexed constraint in the constraint set 
    737                     for ndx in con_set._data: 
    738                         con = con_set._data[ndx] 
    739  
    740                         # Process the body 
    741                         terms = self._process_canonical_repn( 
    742                             generate_canonical_repn(con.body, var_id_map)) 
    743  
    744                         # Process the bounds of the constraint 
    745                         if con._equality: 
    746                             # Equality constraint, only check lower bound 
    747                             lb = self._process_canonical_repn( 
    748                                 generate_canonical_repn(con.lower, var_id_map)) 
    749  
    750                             # Update terms 
    751                             for k in lb: 
    752                                 v = lb[k] 
    753                                 if k in terms: 
    754                                     terms[k] -= v 
    755                                 else: 
    756                                     terms[k] = -v 
    757  
    758                             # Add constraint to equality constraints 
    759                             eqConstraints[(con_set_name, ndx)] = terms 
    760                         else: 
    761  
    762                             # Process upper bounds (<= constraints) 
    763                             if con.upper is not None: 
    764                                 # Less than or equal to constraint 
    765                                 tmp = dict(terms) 
    766  
    767                                 ub = self._process_canonical_repn( 
    768                                     generate_canonical_repn(con.upper, var_id_map)) 
    769  
    770                                 # Update terms 
    771                                 for k in ub: 
    772                                     if k in terms: 
    773                                         tmp[k] -= ub[k] 
    774                                     else: 
    775                                         tmp[k] = -ub[k] 
    776  
    777                                 # Add constraint to less than or equal to 
    778                                 # constraints 
    779                                 leConstraints[(con_set_name, ndx)] = tmp 
    780  
    781                             # Process lower bounds (>= constraints) 
    782                             if con.lower is not None: 
    783                                 # Less than or equal to constraint 
    784                                 tmp = dict(terms) 
    785  
    786                                 lb = self._process_canonical_repn( 
    787                                     generate_canonical_repn(con.lower, var_id_map)) 
    788  
    789                                 # Update terms 
    790                                 for k in lb: 
    791                                     if k in terms: 
    792                                         tmp[k] -= lb[k] 
    793                                     else: 
    794                                         tmp[k] = -lb[k] 
    795  
    796                                 # Add constraint to less than or equal to 
    797                                 # constraints 
    798                                 geConstraints[(con_set_name, ndx)] = tmp 
    799             elif issubclass(c, Objective): 
    800                 # Process objectives 
    801                 objs = self.active_components(c) 
    802  
    803                 # Get the name of the objective, and the objective set itself 
    804                 for obj_set_name in objs: 
    805                     obj_set = objs[obj_set_name] 
    806  
    807                     # For each indexed objective in the objective set 
    808                     for ndx in obj_set._data: 
    809                         obj = obj_set._data[ndx] 
    810                         # Process the objective 
    811                         terms = self._process_canonical_repn( 
    812                             generate_canonical_repn(obj.expr, var_id_map)) 
    813  
    814                         objectives[(obj_set_name, ndx)] = terms 
    815  
    816  
    817         # We now have all the constraints. Add a slack variable for every 
    818         # <= constraint and an excess variable for every >= constraint. 
    819         nSlack = len(leConstraints) 
    820         nExcess = len(geConstraints) 
    821  
    822         nConstraints = len(leConstraints) + len(geConstraints) + \ 
    823                        len(eqConstraints) 
    824         nVariables = len(colID) + nSlack + nExcess 
    825         nRegVariables = len(colID) 
    826  
    827         # Make the arrays 
    828         coefficients = array.array("d", [0]*nConstraints*nVariables) 
    829         constraints = array.array("d", [0]*nConstraints) 
    830         costs = array.array("d", [0]*nVariables) 
    831  
    832         # Populate the coefficient matrix 
    833         constraintID = 0 
    834  
    835         # Add less than or equal to constraints 
    836         for ndx in leConstraints: 
    837             con = leConstraints[ndx] 
    838             for termKey in con: 
    839                 coef = con[termKey] 
    840  
    841                 if termKey is None: 
    842                     # Constraint coefficient 
    843                     constraints[constraintID] = -coef 
    844                 else: 
    845                     # Variable coefficient 
    846                     col = colID[termKey] 
    847                     coefficients[constraintID*nVariables + col] = coef 
    848  
    849             # Add the slack 
    850             coefficients[constraintID*nVariables + nRegVariables + \ 
    851                         constraintID] = 1 
    852             constraintID += 1 
    853  
    854         # Add greater than or equal to constraints 
    855         for ndx in geConstraints: 
    856             con = geConstraints[ndx] 
    857             for termKey in con: 
    858                 coef = con[termKey] 
    859  
    860                 if termKey is None: 
    861                     # Constraint coefficient 
    862                     constraints[constraintID] = -coef 
    863                 else: 
    864                     # Variable coefficient 
    865                     col = colID[termKey] 
    866                     coefficients[constraintID*nVariables + col] = coef 
    867  
    868             # Add the slack 
    869             coefficients[constraintID*nVariables + nRegVariables + \ 
    870                         constraintID] = -1 
    871             constraintID += 1 
    872  
    873         # Add equality constraints 
    874         for ndx in eqConstraints: 
    875             con = eqConstraints[ndx] 
    876             for termKey in con: 
    877                 coef = con[termKey] 
    878  
    879                 if termKey is None: 
    880                     # Constraint coefficient 
    881                     constraints[constraintID] = -coef 
    882                 else: 
    883                     # Variable coefficient 
    884                     col = colID[termKey] 
    885                     coefficients[constraintID*nVariables + col] = coef 
    886  
    887             constraintID += 1 
    888  
    889         # Determine cost coefficients 
    890         for obj_name in objectives: 
    891             obj = objectives[obj_name]() 
    892             for var in obj: 
    893                 costs[colID[var]] = obj[var] 
    894  
    895         # Print the model 
    896         # 
    897         # The goal is to print 
    898         # 
    899         #         var1   var2   var3   ... 
    900         #       +--                     --+ 
    901         #       | cost1  cost2  cost3  ...| 
    902         #       +--                     --+ 
    903         #       +--                     --+ +-- --+ 
    904         # con1  | coef11 coef12 coef13 ...| | eq1 | 
    905         # con2  | coef21 coef22 coef23 ...| | eq2 | 
    906         # con2  | coef31 coef32 coef33 ...| | eq3 | 
    907         #  .    |   .      .      .   .   | |  .  | 
    908         #  .    |   .      .      .    .  | |  .  | 
    909         #  .    |   .      .      .     . | |  .  | 
    910  
    911         constraintPadding = 2 
    912         numFmt = "% 1.4f" 
    913         altFmt = "% 1.1g" 
    914         maxColWidth = max(len(numFmt % 0.0), len(altFmt % 0.0)) 
    915         maxConstraintColWidth = max(len(numFmt % 0.0), len(altFmt % 0.0)) 
    916  
    917         # Generate constraint names 
    918         maxConNameLen = 0 
    919         conNames = [] 
    920         for name in leConstraints: 
    921             strName = str(name) 
    922             if len(strName) > maxConNameLen: 
    923                 maxConNameLen = len(strName) 
    924             conNames.append(strName) 
    925         for name in geConstraints: 
    926             strName = str(name) 
    927             if len(strName) > maxConNameLen: 
    928                 maxConNameLen = len(strName) 
    929             conNames.append(strName) 
    930         for name in eqConstraints: 
    931             strName = str(name) 
    932             if len(strName) > maxConNameLen: 
    933                 maxConNameLen = len(strName) 
    934             conNames.append(strName) 
    935  
    936         # Generate the variable names 
    937         varNames = [None]*len(colID) 
    938         for name in colID: 
    939             tmp_name = " " + name 
    940             if len(tmp_name) > maxColWidth: 
    941                 maxColWidth = len(tmp_name) 
    942             varNames[colID[name]] = tmp_name 
    943         for i in xrange(0, nSlack): 
    944             tmp_name = " _slack_%i" % i 
    945             if len(tmp_name) > maxColWidth: 
    946                 maxColWidth = len(tmp_name) 
    947             varNames.append(tmp_name) 
    948         for i in xrange(0, nExcess): 
    949             tmp_name = " _excess_%i" % i 
    950             if len(tmp_name) > maxColWidth: 
    951                 maxColWidth = len(tmp_name) 
    952             varNames.append(tmp_name) 
    953  
    954         # Variable names 
    955         line = " "*maxConNameLen + (" "*constraintPadding) + " " 
    956         for col in xrange(0, nVariables): 
    957             # Format entry 
    958             token = varNames[col] 
    959  
    960             # Pad with trailing whitespace 
    961             token += " "*(maxColWidth - len(token)) 
    962  
    963             # Add to line 
    964             line += " " + token + " " 
    965         print line 
    966  
    967         # Cost vector 
    968         print " "*maxConNameLen + (" "*constraintPadding) + "+--" + \ 
    969               " "*((maxColWidth+2)*nVariables - 4) + "--+" 
    970         line = " "*maxConNameLen + (" "*constraintPadding) + "|" 
    971         for col in xrange(0, nVariables): 
    972             # Format entry 
    973             token = numFmt % costs[col] 
    974             if len(token) > maxColWidth: 
    975                 token = altFmt % costs[col] 
    976  
    977             # Pad with trailing whitespace 
    978             token += " "*(maxColWidth - len(token)) 
    979  
    980             # Add to line 
    981             line += " " + token + " " 
    982         line += "|" 
    983         print line 
    984         print " "*maxConNameLen + (" "*constraintPadding) + "+--" + \ 
    985               " "*((maxColWidth+2)*nVariables - 4) + "--+" 
    986  
    987         # Constraints 
    988         print " "*maxConNameLen + (" "*constraintPadding) + "+--" + \ 
    989               " "*((maxColWidth+2)*nVariables - 4) + "--+" + \ 
    990               (" "*constraintPadding) + "+--" + \ 
    991               (" "*(maxConstraintColWidth-1)) + "--+" 
    992         for row in xrange(0, nConstraints): 
    993             # Print constraint name 
    994             line = conNames[row] + (" "*constraintPadding) + (" "*(maxConNameLen - len(conNames[row]))) + "|" 
    995  
    996             # Print each coefficient 
    997             for col in xrange(0, nVariables): 
    998                 # Format entry 
    999                 token = numFmt % coefficients[nVariables*row + col] 
    1000                 if len(token) > maxColWidth: 
    1001                     token = altFmt % coefficients[nVariables*row + col] 
    1002  
    1003                 # Pad with trailing whitespace 
    1004                 token += " "*(maxColWidth - len(token)) 
    1005  
    1006                 # Add to line 
    1007                 line += " " + token + " " 
    1008  
    1009             line += "|" + (" "*constraintPadding) + "|" 
    1010  
    1011             # Add constraint vector 
    1012             token = numFmt % constraints[row] 
    1013             if len(token) > maxConstraintColWidth: 
    1014                 token = altFmt % constraints[row] 
    1015  
    1016             # Pad with trailing whitespace 
    1017             token += " "*(maxConstraintColWidth - len(token)) 
    1018  
    1019             line += " " + token + "  |" 
    1020             print line 
    1021         print " "*maxConNameLen + (" "*constraintPadding) + "+--" + \ 
    1022               " "*((maxColWidth+2)*nVariables - 4) + "--+" + \ 
    1023               (" "*constraintPadding) + "+--" + (" "*(maxConstraintColWidth-1))\ 
    1024               + "--+" 
    1025  
    1026         return (coefficients, costs, constraints) 
    1027  
    1028     def _process_canonical_repn(self, expr): 
    1029         """ 
    1030         Returns a dictionary of {var_name_or_None: coef} values 
    1031         """ 
    1032  
    1033         terms = {} 
    1034  
    1035         # Get the variables from the canonical representation 
    1036         vars = expr.pop(-1, {}) 
    1037  
    1038         # Find the linear terms 
    1039         linear = expr.pop(1, {}) 
    1040         for k in linear: 
    1041             # FrozeDicts don't support (k, v)-style iteration 
    1042             v = linear[k] 
    1043  
    1044             # There's exactly 1 variable in each term 
    1045             terms[vars[k.keys()[0]].label] = v 
    1046  
    1047         # Get the constant term, if present 
    1048         const = expr.pop(0, {}) 
    1049         if None in const: 
    1050             terms[None] = const[None] 
    1051  
    1052         if len(expr) != 0: 
    1053             raise TypeError, "Nonlinear terms in expression" 
    1054  
    1055         return terms 
    1056654 
    1057655 
Note: See TracChangeset for help on using the changeset viewer.