source: trunk/coopr/sucasa/main_script.py @ 1515

Last change on this file since 1515 was 1515, checked in by wehart, 11 years ago

Eliminating TODO/TBDs.

File size: 9.5 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
11#
12# This defines the 'run()' function, which is the main
13# script for sucasa.
14#
15
16import sys
17import os
18from optparse import OptionParser
19import traceback
20from ampl_parser import parse_ampl
21from symb_info import MILPSymbInfo
22import sucasa_PICO
23import run_ampl
24import pyutilib
25import re
26
27
28#
29#
30# Setup command-line options
31#
32#
33parser = OptionParser()
34parser.add_option("-k","--keepfiles",
35        help="Keep temporary files",
36        action="store_true",
37        dest="keepfiles",
38        default=False)
39parser.add_option("--acro",
40        help="The directory of the acro installation that will be used to build the customized PICO optimizer.",
41        action="store",
42        dest="acro",
43        default="../..")
44parser.add_option("--name",
45        help="The name of the customized solver application",
46        action="store",
47        dest="name",
48        default=None)
49parser.add_option("-v","--verbose",
50        help="Make output verbose",
51        action="store_true",
52        dest="verbose",
53        default=False)
54parser.add_option("-q","--quiet",
55        help="Make output quiet",
56        action="store_true",
57        dest="quiet",
58        default=False)
59parser.add_option("-p","--parse",
60        help="Parse the AMPL *.mod file, and return immediately",
61        action="store_true",
62        dest="only_parse",
63        default=False)
64parser.add_option("-m","--keep-mapfile",
65        help="Keep the mapfile, if it already exists",
66        action="store_false",
67        dest="overwrite_mapfile",
68        default=True)
69parser.add_option("--mps",
70        help="When specified, SUCASA writes the MILP instances to an MPS file.  By default, it writes an NL file",
71        action="store_true",
72        dest="using_mps",
73        default=False)
74parser.add_option("--protected-vars",
75        help="If this flag is not specified, then the symbols for the variables and arguments are included in the PICO application classes, which may cause symbol conflicts with existing PICO data.  This flag ensures that no symbol classes will occur.",
76        action="store_true",
77        dest="protected",
78        default=False)
79parser.add_option("--without-presolve",
80        help="Disables presolving in AMPL",
81        action="store_false",
82        dest="presolve",
83        default=True)
84parser.add_option("--without-main",
85        help="By default, sucasa includes a main() function in the <app>MILP.cpp file.  This option excludes the main() function.",
86        action="store_false",
87        dest="main",
88        default=True)
89parser.add_option("--solver-options",
90        help="Options for the solver run by SUCASA",
91        action="store",
92        dest="solver_options",
93        default="")
94parser.add_option("-g","--generate",
95        help="Generate the customized IP source files",
96        action="store_true",
97        dest="generate",
98        default=False)
99parser.add_option("-a","--ampl-only",
100        help="Generate the AMPL script, but terminate without calling AMPL.",
101        action="store_true",
102        dest="ampl",
103        default=False)
104parser.add_option("-i","--instance-only",
105        help="Generate a problem instance, and then terminate without calling PICO.",
106        action="store_true",
107        dest="instance",
108        default=False)
109parser.add_option("--np",
110        help="Launch PICO with mpirun if this is specified",
111        action="store",
112        dest="np",
113        default=0)
114parser.usage="sucasa [options] <model.mod> [<model.dat>]"
115parser.description="A utility to generate a customized the PICO integer programming solver that uses application-specific symbolic mapping of the set, parameter, variable and constraint names into the actual data used by the application."
116parser.epilog="""By default, sucasa will extract the variable, objective and constraint names from the AMPL model, and these symbols will be exported to the customized PICO optimizer.  Additionally, sucasa will also export set and parameter symbols declared on lines that contain "SUCASA SYMBOLS". 
117"""
118
119
120def run(args=None):
121    #
122    #
123    # Parse command-line options
124    #
125    #
126    (options, args) = parser.parse_args(args=args)
127    print "Running SUCASA"
128    #
129    # Process arguments
130    #
131    if options.quiet and options.verbose:
132        print "ERROR: cannot have both verbose and quiet output!"
133        return
134    if len(args) == 0:
135        print "ERROR: expected AMPL model file!"
136        print ""
137        parser.print_help()
138        return
139    if len(args) > 2:
140        print "ERROR: expect one or two arguments!"
141        print "Arguments: " + " ".join(args)
142        return
143    if options.name is None:
144        (path,filename) = os.path.split(args[0])
145        (basename,ext) = os.path.splitext(filename)
146        options.name = basename
147    if "-" in options.name:
148        print "  WARNING: replacing '-' in application name with '_'"
149        options.name = "_".join(options.name.split('-'))
150   
151    #
152    # Parse model file, and generate customized solver
153    #
154    parse_info = None
155    print "  . Parsing AMPL model '"+args[0]+"'"
156    try:
157        if options.verbose:
158            debug=100
159        else:
160            debug=0
161        parse_info = parse_ampl(filename=args[0],debug=debug)
162    except IOError, err:
163        print "      Error parsing file "+args[0]
164        print "      "+str(err)
165        return
166    #
167    # Print parser info and return
168    #
169    if options.only_parse:
170        print "SUCASA Parse Info"
171        print str(parse_info)
172        return
173    #
174    # Setup the symbolic information class
175    #
176    print "  . Processing model information"
177    symbolic_info = MILPSymbInfo()
178    symbolic_info.name = options.name
179    symbolic_info.verbose = options.verbose
180    try:
181        parse_info.initialize(symbolic_info)   
182    except IOError, err:
183        print "Caught an IO exception: "+str(err)
184        return
185
186    #
187    # Generate the customized solver
188    #
189    if options.generate:
190        #
191        # Write the *.map file and source files
192        #
193        if options.overwrite_mapfile or not os.path.exists(symbolic_info.name+".map"):
194            filename = symbolic_info.write_mapfile()
195            print "  . Created mapfile '"+filename+"'"
196        else:
197            print "  . Using existing mapfile: "+symbolic_info.name+".map"
198            symbolic_info = MILPSymbInfo()
199            symbolic_info.name = options.name
200            symbolic_info.read_mapfile(symbolic_info.name+".map")
201            #
202            # Perform consistency check between symbolic_info and parse_info
203            #
204            if parse_info.check(symbolic_info):
205                print "      Consistency check with parse information is OK"
206            else:
207                print "      Consistency check with parse information has FAILED!"
208                return
209            parse_info.update_exports()
210        #
211        # Generate source files
212        #
213        print "  . Generating source code for customized optimizer:"
214        symb_files = symbolic_info.generate_milp_symbol_code()
215        opt_files = sucasa_PICO.create_customized_files(app_label=symbolic_info.name, create_main=options.main, protected=options.protected, acro_dir=options.acro)
216        for file in symb_files+opt_files:
217            print "      "+file
218        return
219
220    #
221    # Apply the customized solver to a dataset
222    #
223    (path,filename) = os.path.split(args[0])
224    (basename,ext) = os.path.splitext(filename)
225    if ext != ".mod":
226        print "ERROR: Expecting first argument to be an AMPL model: "+args[0]
227        return
228    if len(args)==2:
229        (path,filename) = os.path.split(args[1])
230        (basename,ext) = os.path.splitext(filename)
231        if ext != ".dat":
232            print "ERROR: Expecting second argument to be an AMPL data file: "+args[1]
233            return
234        datafile=args[1]
235    else:
236        datafile=None
237    #
238    # Run AMPL
239    #
240    try:
241        symbols=[]
242        for item in parse_info.items:
243            if item[0] in ("set","param") and parse_info.concrete[item[1]] and ('*' in parse_info.exported_symbols or item[1] in parse_info.exported_symbols):
244                symbols.append(item[1])
245        run_ampl.run_ampl(symbols=symbols, app_label=options.name, model_file=args[0], data_file=datafile, presolve=options.presolve, keepFiles=options.keepfiles, using_mps=options.using_mps, only_script=options.ampl)
246    except IOError, err:
247        print "      "+str(err)
248        return
249    if options.ampl:
250        print "  . Terminated after generating AMPL script"
251        return
252    #
253    # Run PICO
254    #
255    if not options.instance:
256        cmd=""
257        if options.np > 0:
258            cmd = "mpirun -np "+str(options.np)+" "
259        else:
260            cmd = "./"
261        cmd+="PICO_"+options.name+" "+options.solver_options+" "+options.name
262        if options.using_mps:
263            cmd += ".mps"
264        else:
265            cmd += ".nl"
266        print "  . PICO Command: "+cmd
267        print "  . Running PICO ...",
268        pyutilib.run_command(cmd,"PICO.out")
269        print "done."
270        if options.quiet:
271            print "    Output in file 'PICO.out'"
272        else:
273            INPUT = open("PICO.out")
274            for line in INPUT:
275                print line,
276            INPUT.close()
277
Note: See TracBrowser for help on using the repository browser.