00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <fstream>
00023 #include <cstdlib>
00024 #include <getopt.h>
00025 #include <utility>
00026 #include <sstream>
00027 #include <limits>
00028
00029 #include "driver.hh"
00030 #include "bounds.hh"
00031 #include "mipgen.hh"
00032 #include "mpsgen.hh"
00033 #include "opbgen.hh"
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045 driver::driver()
00046 : multiply_k(false),
00047 gamma_constraint(false),
00048 max_order(10),
00049 min_order(1),
00050 format("mps"),
00051 trace_scanning(false),
00052 trace_parsing(false)
00053 {
00054 }
00055
00056
00057
00058
00059
00060
00061 driver::~driver() {
00062 }
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077 void driver::usage(const char* cmd, std::ostream& out) {
00078 out << "Usage: " << cmd << " [opts] [files...]" << std::endl
00079 << "Options:" << std::endl
00080 << " -f --format=STR choose output format STR" << std::endl
00081 << " -g --gamma Disallow single fractional gamma" << std::endl
00082 << " -h --help display this help you see now" << std::endl
00083 << " -k --multiply-k multiply all n_* by k" << std::endl
00084 << " -l --min-order=INT specify left hand side of limiting row" << std::endl
00085 << " -m --max-order=INT specify right hand side of limiting row" << std::endl
00086 << "Formats:" << std::endl
00087 << " mps common format for linear and mixed integer optimization" << std::endl
00088 << " opb format for the opbdp pseudo boolean optimizer" << std::endl
00089 << " csv tabbed text for spreadsheet applications" << std::endl
00090 ;
00091 }
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103 void driver::parse_opts(int argc, char** argv) {
00104 int trace_scanning = 0, trace_parsing = 0;
00105 struct option opts[] = {
00106 { "format" , required_argument, NULL, 'f' },
00107 { "gamma" , no_argument, NULL, 'g' },
00108 { "help" , no_argument, NULL, 'h' },
00109 { "multiply-k" , no_argument, NULL, 'k' },
00110 { "min-order" , required_argument, NULL, 'l' },
00111 { "max-order" , required_argument, NULL, 'm' },
00112 { "trace-scanning", no_argument, &trace_scanning, 1 },
00113 { "trace-parsing" , no_argument, &trace_parsing , 1 },
00114 { 0, 0, 0, 0 }
00115 };
00116
00117 for (;;) {
00118 int index = 0;
00119 int chr = getopt_long(argc, argv, "f:ghkl:m:", opts, &index);
00120 if (chr == -1) break;
00121 switch (chr) {
00122 case 0:
00123
00124
00125 break;
00126 case 'f':
00127 format = optarg;
00128 if (format != "mps" && format != "opb" && format != "csv") {
00129 std::cerr << "Unsupported format: " << format << std::endl;
00130 exit(EXIT_FAILURE);
00131 }
00132 break;
00133 case 'g':
00134 gamma_constraint = true;
00135 break;
00136 case 'h':
00137 usage(argv[0], std::cout);
00138 exit(EXIT_SUCCESS);
00139 break;
00140 case 'k':
00141 multiply_k = true;
00142 break;
00143 case 'l':
00144 min_order = atoi(optarg);
00145 break;
00146 case 'm':
00147 max_order = atoi(optarg);
00148 break;
00149 default:
00150 usage(argv[0], std::cerr);
00151 exit(EXIT_FAILURE);
00152 }
00153 }
00154
00155 this->trace_scanning = trace_scanning;
00156 this->trace_parsing = trace_parsing;
00157
00158 if (optind < argc) {
00159 while (optind < argc)
00160 parse_file(argv[optind++]);
00161 }
00162 else {
00163 parse_stdin();
00164 }
00165 }
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175 void driver::parse_file(const char *infile) {
00176 std::ifstream in(infile);
00177 parse(infile, in);
00178 in.close();
00179 if (errorCount) return;
00180 std::string outfile(infile);
00181 if (outfile.find(".mqn", outfile.size() - 4) == outfile.size() - 4)
00182 outfile.erase(outfile.size() - 3);
00183 outfile.append(format);
00184 process(outfile.c_str());
00185 }
00186
00187
00188
00189
00190
00191
00192
00193
00194 void driver::parse_stdin() {
00195 parse("<stdin>", std::cin);
00196 if (errorCount) return;
00197 process(0);
00198 }
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209 void driver::parse(const char* file, std::istream& in) {
00210 errorCount = 0;
00211 this->file = file;
00212
00213 yy::lexer lexer(*this, &in, &std::cerr);
00214 this->theLexer = &lexer;
00215 lexer.set_debug(trace_scanning);
00216
00217 yy::parser parser(*this);
00218 parser.set_debug_level(trace_parsing);
00219 if (parser.parse()) ++errorCount;
00220
00221 this->theLexer = 0;
00222 this->file = "<closed>";
00223 }
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234 void driver::error(const yy::location& location, const std::string& message) {
00235 std::cerr << location << ": " << message << std::endl;
00236 errorCount++;
00237 }
00238
00239
00240
00241
00242
00243
00244
00245
00246 void driver::error(const std::string& message) {
00247 std::cerr << message << std::endl;
00248 errorCount++;
00249 }
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264 void driver::set_names(const yy::location& location,
00265 std::vector<std::string>* qns) {
00266 std::swap(names, *qns);
00267 delete qns;
00268 indices.clear();
00269 for (int i = 0; i < (int)names.size(); ++i) {
00270 if (names[i].empty()) {
00271 error(location, "names must not be empty");
00272 }
00273 if (names[i][0] == '_') {
00274 error(location, "names beginning with _ are reserved");
00275 }
00276 if (!indices.insert(make_pair(names[i], i)).second) {
00277 error(location, "duplicate name: " + names[i]);
00278 }
00279 }
00280 if (multiply_k && indices.find("k") == indices.end()) {
00281 error(location, "no element named k to multiply n_i");
00282 }
00283 if (gamma_constraint && indices.find("gamma") == indices.end()) {
00284 error(location, "no element named gamma for special gamma constraint");
00285 }
00286 }
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300 void driver::set_constraints(const yy::location& location,
00301 std::vector<constraint>* css) {
00302 std::swap(constraints, *css);
00303 delete css;
00304 typedef std::vector<constraint>::iterator iter;
00305 for (iter i = constraints.begin(), e = constraints.end(); i != e; ++i) {
00306 if (indices.find(i->name) == indices.end()) {
00307 error(location, "no such name: " + i->name);
00308 }
00309 }
00310 }
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323 void driver::set_fields(const yy::location&,
00324 std::vector<field>* vcs) {
00325 std::swap(fields, *vcs);
00326 delete vcs;
00327 }
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346 field* driver::checked_field(const yy::location& location,
00347 std::string* name,
00348 std::vector<rational>* rationals) {
00349 if (name->empty()) {
00350 error(location, "names must not be empty");
00351 }
00352 if ((*name)[0] == '_') {
00353 error(location, "names beginning with _ are reserved");
00354 }
00355 if (rationals->size() == names.size()) {
00356 return new field(name, rationals);
00357 }
00358 else {
00359 std::ostringstream ss;
00360 if (rationals->size() < names.size())
00361 ss << "too few";
00362 else
00363 ss << "too many";
00364 ss << " entries in field " << *name
00365 << ": expected " << names.size() << " but found " << rationals->size();
00366 error(location, ss.str());
00367 delete name;
00368 delete rationals;
00369 return 0;
00370 }
00371 }
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382 void driver::result(const yy::location&,
00383 std::string* name) {
00384 std::swap(this->name, *name);
00385 delete name;
00386 }
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397 void driver::process(const char* file) {
00398 mipgen *gen;
00399 if (format == "opb") gen = new opbgen(*this);
00400 else if (format == "mps") gen = new mpsgen(*this);
00401 else gen = new mipgen(*this);
00402 gen->formulate();
00403 gen->write(file);
00404 delete gen;
00405 }