source: coopr.pyomo/trunk/coopr/pyomo/data/process_data.py @ 3009

Last change on this file since 3009 was 3009, checked in by wehart, 9 years ago

Setting up plugins for database interfaces.

File size: 19.4 KB
Line 
1#  _________________________________________________________________________
2#
3#  Coopr: A COmmon Optimization Python Repository
4#  Copyright (c) 2008 Sandia Corporation.
5#  This software is distributed under the BSD License.
6#  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
7#  the U.S. Government retains certain rights in this software.
8#  For more information, see the Coopr README.txt file.
9#  _________________________________________________________________________
10
11import re
12import copy
13import math
14from parse_datacmds import parse_data_commands
15from pyutilib.misc import quote_split, Options
16from coopr.pyomo.base.plugin import *
17from coopr.pyomo.base import pyomo
18from coopr.pyomo.base.plugin import *
19
20global Lineno
21global Filename
22
23
24def _preprocess_data(cmd):
25        """
26        Called by _process_data() to (1) combine tokens that comprise a tuple
27        and (2) combine the ':' token with the previous token
28        """
29        if pyomo.debug("reader"):               #pragma:nocover
30           print "_preprocess_data(start)",cmd
31        status=")"
32        newcmd=[]
33        for token in cmd:
34          if type(token) in (str,unicode):
35             token=str(token)
36             if "(" in token and ")" in token:
37                newcmd.append(token)
38                status=")"
39             elif "(" in token:
40                if status == "(":
41                   raise ValueError, "Two '('s follow each other in data "+token
42                status="("
43                newcmd.append(token)
44             elif ")" in token:
45                if status == ")":
46                   raise ValueError, "Two ')'s follow each other in data"
47                status=")"
48                newcmd[-1] = newcmd[-1]+token
49             elif status == "(":
50                newcmd[-1] = newcmd[-1]+token
51             else:
52                newcmd.append(token)
53          else:
54             if type(token) is float and math.floor(token) == token:
55                token=int(token)
56             newcmd.append(token)
57        if pyomo.debug("reader"):               #pragma:nocover
58           print "_preprocess_data(end)",newcmd
59        return newcmd
60
61
62def _process_set(cmd, _model, _data):
63        """
64        Called by _process_data() to process a set declaration.
65        """
66        if pyomo.debug("reader"):               #pragma:nocover
67           print "DEBUG: _process_set(start)",cmd
68        #
69        # Process a set
70        #
71        if "[" in cmd[1]:
72           tokens = re.split("[\[\]]",cmd[1])
73           ndx=tokens[1]
74           ndx=tuple(_data_eval(ndx.split(",")))
75           if tokens[0] not in _data:
76              _data[tokens[0]] = {}
77           _data[tokens[0]][ndx] = _process_set_data(cmd[3:], tokens[0], _model)
78        elif cmd[2] == ":":
79           _data[cmd[1]] = {}
80           _data[cmd[1]][None] = []
81           i=3
82           while cmd[i] != ":=":
83              i += 1
84           ndx1 = cmd[3:i]
85           i += 1
86           while i<len(cmd):
87              ndx=cmd[i]
88              for j in range(0,len(ndx1)):
89                if cmd[i+j+1] == "+":
90                   _data[cmd[1]][None] += _process_set_data(["("+str(ndx1[j])+","+str(cmd[i])+")"], cmd[1], _model)
91              i += len(ndx1)+1
92        else:
93           _data[cmd[1]] = {}
94           _data[cmd[1]][None] = _process_set_data(cmd[3:], cmd[1], _model)
95
96
97def _process_set_data(cmd, sname, _model):
98        """
99        Called by _process_set() to process set data.
100        """
101        if pyomo.debug("reader"):               #pragma:nocover
102           print "DEBUG: _process_set_data(start)",cmd
103        if len(cmd) == 0:
104           return []
105        try:
106            sd = getattr(_model,sname)
107        except AttributeError:
108            raise IOError, "Cannot process data for set '%s' because it is not defined in model '%s'" % (sname, _model.name)
109        #d = sd.dimen
110        cmd = _data_eval(cmd)
111        ans=[]
112        i=0
113        flag=type(cmd[0]) is tuple
114        tmp=None
115        ndx=None
116        while i<len(cmd):
117          if type(cmd[i]) is not tuple:
118            if flag:
119               #if type(cmd[i]) is not tuple:
120               #   raise ValueError, "Problem initializing set="+sname+" with input data="+str(cmd)+" - first element was interpreted as a tuple, but element="+str(i)+" is of type="+str(type(cmd[i]))+"; types must be consistent"
121               tmpval=tmp
122               tmpval[ndx] = _data_eval([cmd[i]])[0]
123               #
124               # WEH - I'm not sure what the next two lines are for
125               #        These are called when initializing a set with more than
126               #        one dimension
127               #if d > 1:
128               #   tmpval = util.tuplize(tmpval,d,sname)
129               ans.append(tuple(tmpval))
130            else:
131               ans.append(cmd[i])
132          elif "*" not in cmd[i]:
133            ans.append(cmd[i])
134          else:
135            j = i
136            tmp=list(cmd[j])
137            ndx=tmp.index("*")
138          i += 1
139        if pyomo.debug("reader"):               #pragma:nocover
140           print "DEBUG: _process_set_data(end)",ans
141        return ans
142
143
144def _process_param(cmd, _model, _data, _default):
145        """
146        Called by _process_data to process data for a Parameter declaration
147        """
148        if pyomo.debug("reader"):               #pragma:nocover
149           print "DEBUG: _process_param(start)",cmd
150        #
151        # Process parameters
152        #
153        dflt = None
154        singledef = True
155        cmd = cmd[1:]
156        if cmd[0] == ":":
157           singledef = False
158           cmd = cmd[1:]
159        if singledef:
160           pname = cmd[0]
161           cmd = cmd[1:]
162           if len(cmd) >= 2 and cmd[0] == "default":
163              dflt = _data_eval(cmd[1])[0]
164              cmd = cmd[2:]
165           if dflt != None:
166              _default[pname] = dflt
167           if cmd[0] == ":=":
168              cmd = cmd[1:]
169           transpose = False
170           if cmd[0] == "(tr)":
171              transpose = True
172              if cmd[1] == ":":
173                 cmd = cmd[1:]
174              else:
175                 cmd[0] = ":"
176           if cmd[0] != ":":
177              if pyomo.debug("reader"):             #pragma:nocover
178                 print "DEBUG: _process_param (singledef without :...:=)",cmd
179              if not transpose:
180                 if pname not in _data:
181                    _data[pname] = {}
182                 finaldata = _process_data_list(getattr(_model,pname).dim(), _data_eval(cmd))
183                 for key in finaldata:
184                    _data[pname][key]=finaldata[key]
185              else:
186                 tmp = ["param", pname, ":="]
187                 i=1
188                 while i < len(cmd):
189                    i0 = i
190                    while cmd[i] != ":=":
191                      i=i+1
192                    ncol = i - i0 + 1
193                    lcmd = i
194                    while lcmd < len(cmd) and cmd[lcmd] != ":":
195                      lcmd += 1
196                    j0 = i0 - 1
197                    for j in range(1,ncol):
198                      ii = 1 + i
199                      kk = ii + j
200                      while kk < lcmd:
201                        if cmd[kk] != ".":
202                        #if 1>0:
203                           tmp.append(copy.copy(cmd[j+j0]))
204                           tmp.append(copy.copy(cmd[ii]))
205                           tmp.append(copy.copy(cmd[kk]))
206                        ii = ii + ncol
207                        kk = kk + ncol
208                    i = lcmd + 1
209                 _process_param(tmp, _model, _data, _default)
210           else:
211              tmp = ["param", pname, ":="]
212              i=1
213              if pyomo.debug("reader"):             #pragma:nocover
214                 print "DEBUG: _process_param (singledef with :...:=)",cmd
215              while i < len(cmd):
216                i0 = i
217                while i<len(cmd) and cmd[i] != ":=":
218                  i=i+1
219                if i==len(cmd):
220                   raise ValueError, "ERROR: Trouble on line "+str(Lineno)+" of file "+Filename
221                ncol = i - i0 + 1
222                lcmd = i
223                while lcmd < len(cmd) and cmd[lcmd] != ":":
224                  lcmd += 1
225                j0 = i0 - 1
226                for j in range(1,ncol):
227                  ii = 1 + i
228                  kk = ii + j
229                  while kk < lcmd:
230                    if cmd[kk] != ".":
231                        if transpose:
232                           tmp.append(copy.copy(cmd[j+j0]))
233                           tmp.append(copy.copy(cmd[ii]))
234                        else:
235                           tmp.append(copy.copy(cmd[ii]))
236                           tmp.append(copy.copy(cmd[j+j0]))
237                        tmp.append(copy.copy(cmd[kk]))
238                    ii = ii + ncol
239                    kk = kk + ncol
240                i = lcmd + 1
241                _process_param(tmp, _model, _data, _default)
242
243        else:
244           if pyomo.debug("reader"):                #pragma:nocover
245              print "DEBUG: _process_param (cmd[0]=='param:')",cmd
246           i=0
247           nsets=0
248           while i<len(cmd) and cmd[i] != ":=":
249             if cmd[i] == ":":
250                nsets = i
251             i += 1
252           if i==len(cmd):
253              raise ValueError, "Trouble on data file line "+str(Lineno)+" of file "+Filename
254           if pyomo.debug("reader"):                #pragma:nocover
255              print "NSets",nsets
256           Lcmd = len(cmd)
257           j=0
258           d = 1
259           #
260           # Process sets first
261           #
262           while j<nsets:
263             sname = cmd[j]
264             d = getattr(_model,sname).dimen
265             np = i-1
266             if pyomo.debug("reader"):              #pragma:nocover
267                print "I,J,SName,d",i,j,sname,d
268             dnp = d + np - 1
269             #k0 = i + d - 2
270             ii = i + j + 1
271             tmp = [ "set", cmd[j], ":=" ]
272             while ii < Lcmd:
273               for dd in range(0,d):
274                 tmp.append(copy.copy(cmd[ii+dd]))
275               ii += dnp
276             _process_set(tmp, _model, _data)
277             j += 1
278           if nsets > 0:
279              j += 1
280           #
281           # Process parameters second
282           #
283           while j < i:
284             pname = cmd[j]
285             if pyomo.debug("reader"):              #pragma:nocover
286                print "I,J,Pname",i,j,pname
287             #d = 1
288             d = getattr(_model,pname).dim()
289             if nsets > 0:
290                np = i-1
291                dnp = d+np-1
292                ii = i + 1
293                kk = i + d + j-1
294             else:
295                np = i
296                dnp = d + np
297                ii = i + 1
298                kk = np + 1 + d + nsets + j
299             tmp = [ "param", pname, ":=" ]
300             if pyomo.debug("reader"):              #pragma:nocover
301                print "dnp",dnp
302                print "np",np
303             while kk < Lcmd:
304               if pyomo.debug("reader"):                #pragma:nocover
305                  print "kk,ii",kk,ii
306               iid = ii + d
307               while ii < iid:
308                 tmp.append(copy.copy(cmd[ii]))
309                 ii += 1
310               ii += dnp-d
311               tmp.append(copy.copy(cmd[kk]))
312               kk += dnp
313             _process_param(tmp, _model, _data, _default)
314             j += 1
315
316
317def _process_data_list(dim, cmd):
318        """
319        Called by _process_param() to process a list of data for a
320        Parameter.
321        """
322        if pyomo.debug("reader"):               #pragma:nocover
323           print "process_data_list",dim,cmd
324        if len(cmd) % (dim+1) != 0:
325           raise ValueError, "Parameter data has "+str(len(cmd))+" values (" + str(cmd) + "), which is incompatible with having "+str(dim)+" dimensions"           
326        ans={}
327        if dim==0:
328           ans[None]=cmd[0]
329           return ans
330        i=0
331        while i<len(cmd):
332          ndx = tuple(cmd[i:i+dim])
333          ##print i,cmd[i:i+dim],ndx,cmd[i+dim]
334          if cmd[i+dim] != ".":
335                 ans[ndx] = cmd[i+dim]
336          i += dim+1
337        return ans
338
339
340def _data_eval(values):
341        """
342        Evaluate the list of values to make them bool, integer or float,
343        or a tuple value.
344        """
345        if pyomo.debug("reader"):               #pragma:nocover
346           print "DEBUG: _data_eval(start)",values
347        ans = []
348        for val in values:
349          if type(val) in (bool,int,float,long):
350             ans.append(val)
351             continue
352          if val in ('True','true','TRUE'):
353             ans.append(True)
354             continue
355          if val in ('False','false','FALSE'):
356             ans.append(False)
357             continue
358          tmp = None
359          if "(" in val and ")" in val:
360             vals = []
361             tval = val[1:-1]
362             for item in tval.split(","):
363               tmp=_data_eval([item])
364               vals.append(tmp[0])
365             ans.append(tuple(vals))
366             continue
367          try:
368             tmp = int(val)
369             ans.append(tmp)
370          except ValueError:
371             pass
372          if tmp is None:
373             try:
374               tmp = float(val)
375               ans.append(tmp)
376             except ValueError:
377               ans.append(val)
378        if pyomo.debug("reader"):               #pragma:nocover
379           print "DEBUG: _data_eval(end)",ans
380        return ans
381
382
383def _process_include(cmd, _model, _data, _default):
384    if len(cmd) == 1:
385        raise IOError, "Cannot execute 'include' command without a filename"
386    if len(cmd) > 2:
387        raise IOError, "The 'include' command only accepts a single filename"
388
389    global Filename
390    Filename = cmd[1]
391    global Lineno
392    Lineno = 0
393
394    try:
395        scenarios = parse_data_commands(filename=cmd[1])
396    except IOError, err:
397        raise IOError, "Error parsing file '%s': %s" % (Filename, str(err))
398    if scenarios is None:
399        return False
400    for scenario in scenarios:
401        for cmd in scenarios[scenario]:
402            #print "SCENARIO",scenario,"CMD",cmd
403            if scenario not in _data:
404                _data[scenario] = {}
405            #print "X _data",_data
406            if cmd[0] in ('include', 'import'):
407                _tmpdata = {}
408                _process_data(cmd, _model, _tmpdata, _default, Filename, Lineno)
409                #print "X _tmpdata",_tmpdata
410                if scenario is None:
411                    for key in _tmpdata:
412                        if key in _data:
413                            _data[key].update(_tmpdata[key])
414                        else:
415                            _data[key] = _tmpdata[key]
416                else:
417                    for key in _tmpdata:
418                        if key is None:
419                            _data[scenario].update(_tmpdata[key])
420                        else:
421                            raise IOError, "Cannot define a scenario within another scenario"
422            else:
423                _process_data(cmd, _model, _data[scenario], _default, Filename, Lineno)
424            #print "X _data update",_data
425    return True
426
427
428def X_process_include(cmd, _model, _data, _default):
429    if len(cmd) == 1:
430        raise IOError, "Cannot execute 'include' command without a filename"
431    if len(cmd) > 2:
432        raise IOError, "The 'include' command only accepts a single filename"
433
434    global Filename
435    Filename = cmd[1]
436    global Lineno
437    Lineno = 0
438    cmd=""
439    status=True
440    INPUT=open(Filename,'r')
441    for line in INPUT:
442        Lineno = Lineno + 1
443        line = re.sub(":"," :",line)
444        line = line.strip()
445        if line == "" or line[0] == '#':
446            continue
447        cmd = cmd + " " + line
448        if ';' in cmd:
449            #
450            # We assume that a ';' indicates an end-of-command declaration.
451            # However, the user might have put multiple commands on a single
452            # line, so we need to split the line based on these values.
453            # BUT, at the end of the line we should see an 'empty' command,
454            # which we ignore.
455            #
456            for item in cmd.split(';'):
457                item = item.strip()
458                if item != "":
459                    _process_data(quote_split("[\t ]+",item), _model, _data, _default, Filename, Lineno)
460                cmd = ""
461    if cmd != "":
462        INPUT.close()
463        raise IOError, "ERROR: There was unprocessed text at the end of the data file!: \"" + cmd + "\""
464    INPUT.close()
465    return status
466
467
468def _process_import(cmd, _model, _data, _default):
469    #print "IMPORT",cmd
470    if len(cmd) < 2:
471        raise IOError, "The 'import' command must specify a filename"
472
473    options = Options(**cmd[1])
474    for key in options:
475        if not key in ['range','filename','format','using','query','user','password']:
476            raise ValueError, "Unknown import option '%s'" % key
477
478    global Filename
479    Filename = cmd[1]
480    global Lineno
481    Lineno = 0
482
483    #
484    # TODO: process mapping info
485    #
486    if options.using is None:
487        tmp = options.filename.split(".")[-1]
488        data = DataManagerFactory(tmp)
489    else:
490        data = DataManagerFactory(options.using)
491    set_name=None
492    param_name=None
493    #
494    # Create symbol map
495    #
496    symb_map = cmd[3]
497    if len(symb_map) == 0:
498        raise IOError, "Must specify at least one set or parameter name that will be imported"
499    #
500    # Process index data
501    #
502    index=cmd[2][1]
503    index_name=cmd[2][0]
504    #
505    # Set the 'set name' based on the format
506    #
507    if options.format == 'set' or options.format == 'set_array':
508        if len(cmd[3]) != 1:
509            raise IOError, "A single set name must be specified when using format '%s'" % options.format
510        set_name=cmd[3].keys()[0]
511    else:
512        set_name=None
513    #
514    # Set the 'param name' based on the format
515    #
516    if options.format == 'transposed_array' or options.format == 'array' or options.format == 'param':
517        if len(cmd[3]) != 1:
518            raise IOError, "A single parameter name must be specified when using format '%s'" % options.format
519        param_name = cmd[3].keys()[0]
520    else:
521        param_name = None
522    #
523    data.initialize(options.filename, index=index, index_name=index_name, param_name=symb_map, set=set_name, param=param_name, format=options.format, range=options.range, query=options.query, using=options.using)
524    #
525    data.open()
526    try:
527        data.read()
528    except Exception, e:
529        data.close()
530        raise e
531    data.close()
532    print "Y",_data
533    data.process(_model, _data, _default)
534    #print "Y",_data
535       
536   
537
538
539def _process_data(cmd, _model, _data, _default, Filename_, Lineno_=0):
540        """
541        Called by import_file() to (1) preprocess data and (2) call
542        subroutines to process different types of data
543        """
544        #print "CMD",cmd
545        global Lineno
546        global Filename
547        Lineno=Lineno_
548        Filename=Filename_
549
550        if pyomo.debug("reader"):               #pragma:nocover
551           print "DEBUG: _process_data (start)",cmd
552        if len(cmd) == 0:                       #pragma:nocover
553           raise ValueError, "ERROR: Empty list passed to Model::_process_data"
554
555        cmd = _preprocess_data(cmd)
556
557        if cmd[0] == "data":
558           return True
559        if cmd[0] == "end":
560           return False
561        if cmd[0].startswith('set'):
562           _process_set(cmd, _model, _data)
563        elif cmd[0].startswith('param'):
564           _process_param(cmd, _model, _data, _default)
565        elif cmd[0] == 'include':
566           _process_include(cmd, _model, _data, _default)
567        elif cmd[0] == 'import':
568           _process_import(cmd, _model, _data, _default)
569        else:
570           raise IOError, "ERROR: Unknown data command: "+" ".join(cmd)
571        return True
572
573
Note: See TracBrowser for help on using the repository browser.