Timetabler
main.cpp
1 #include <getopt.h>
2 #include <iomanip>
3 #include <iostream>
4 #include <string>
5 #include "constraint_adder.h"
6 #include "constraint_encoder.h"
7 #include "core/Solver.h"
8 #include "custom_parser.h"
9 #include "global.h"
10 #include "global_vars.h"
11 #include "mtl/Vec.h"
12 #include "parser.h"
13 #include "utils.h"
14 #include "version.h"
15 
21 void display_meta(bool display_desc = false) {
22  std::cout << "Timetabler version " __TIMETABLER_VERSION__ << std::endl;
23  if (display_desc)
24  std::cout << "\n"
25  << "A highly customizable timetabling software for educational\n"
26  "institutions that encodes timetabling constraints as a SAT\n"
27  "formula and solves them using a MaxSAT solver."
28  << std::endl;
29 }
30 
34 const struct option long_options[] = {{"help", no_argument, 0, 'h'},
35  {"fields", required_argument, 0, 'f'},
36  {"input", required_argument, 0, 'i'},
37  {"custom", required_argument, 0, 'c'},
38  {"output", required_argument, 0, 'o'},
39  {"verbosity", required_argument, 0, 'b'},
40  {"version", no_argument, 0, 'v'},
41  {0, 0, 0, 0}};
42 
46 const std::string option_desc[] = {"display this help",
47  "fields yaml file",
48  "input csv file",
49  "custom constraints file",
50  "output csv file",
51  "specify verbosity level (0-3)"
52  "display version",
53  ""};
54 
60 void display_help(std::string exec = "timetabler") {
61  display_meta(true);
62  std::cout << "\nUsage:\n";
63  std::cout << " " << exec
64  << " -i|--input <input_file>"
65  " -f|--fields <fields_file>"
66  " [-c|--custom <custom_constraints_file>]"
67  " -o|--output <output_file>"
68  "\n\n";
69  std::cout << "Options:\n";
70  for (int i = 0; long_options[i].name != 0; i++) {
71  if (long_options[i].val)
72  std::cout << '-' << char(long_options[i].val) << ", ";
73  std::cout << std::left << "--" << std::setw(8) << long_options[i].name
74  << "\t" << option_desc[i] << "\n";
75  }
76 }
77 
83 void display_error(std::string err) {
84  std::cout << err << std::endl;
85  std::cout << "Use --help option to know about supported options."
86  << std::endl;
87  exit(1);
88 }
89 
91 
100 int main(int argc, char *const *argv) {
101  std::string input_file, fields_file, custom_file, output_file;
102  unsigned verbosity = 3;
103 
104  while (1) {
105  int option_index = 0;
106  int c =
107  getopt_long(argc, argv, "hi:f:c:o:b:v", long_options, &option_index);
108 
109  if (c == -1) break;
110 
111  switch (c) {
112  case 0:
113  break;
114  case 'h':
115  display_help(std::string(argv[0]));
116  exit(0);
117  case 'v':
118  display_meta();
119  exit(0);
120  case 'i':
121  input_file = std::string(optarg);
122  break;
123  case 'f':
124  fields_file = std::string(optarg);
125  break;
126  case 'c':
127  custom_file = std::string(optarg);
128  break;
129  case 'o':
130  output_file = std::string(optarg);
131  break;
132  case 'b':
133  verbosity = std::stoi(optarg);
134  break;
135  case '?':
136  break;
137  default:
138  display_error("Unrecognised argument: " + std::to_string(c));
139  }
140  }
141 
142  Utils::Log::setVerbosity(verbosity);
143 
144  if (optind < argc) {
145  display_error("Unrecognised argument: " + std::string(argv[optind]));
146  }
147 
148  if (input_file == "" || fields_file == "" || output_file == "") {
149  display_error(
150  "Fields filename, input filename and output filename are required.");
151  }
152 
153  timetabler = new Timetabler();
154  Parser parser(timetabler);
155  parser.parseFields(fields_file);
156  parser.parseInput(input_file);
157  if (parser.verify()) {
158  LOG(INFO) << "Input is valid";
159  } else {
160  LOG(ERROR) << "Input is invalid";
161  }
162  parser.addVars();
163  ConstraintEncoder encoder(timetabler);
164  ConstraintAdder constraintAdder(&encoder, timetabler);
165  constraintAdder.addConstraints();
166  if (custom_file != "") {
167  parseCustomConstraints(custom_file, &encoder, timetabler);
168  LOG(INFO) << "Custom constraints parsed.";
169  }
170  timetabler->addHighLevelClauses();
171  timetabler->addExistingAssignments();
172  SolverStatus solverStatus = timetabler->solve();
173  timetabler->printResult(solverStatus);
174  if (solverStatus == SolverStatus::Solved ||
175  solverStatus == SolverStatus::HighLevelFailed) {
176  timetabler->writeOutput(output_file);
177  }
178  delete timetabler;
179  return 0;
180 }
void addConstraints()
Adds all the constraints with their respective weights using the Timetabler object to the solver...
static void setVerbosity(int verb)
Sets the verbosity level for logging. (0 - EMPTY, 1 - ERROR, 2 - WARNING, 3 - INFO). All messages of levels in and below the current verbosity level are displayed in the output.
Definition: utils.cpp:258
void addExistingAssignments()
Adds unit clauses corresponding to existing assignments given in the input to the solver...
Definition: timetabler.cpp:118
void addHighLevelClauses()
Adds unit soft clauses for the high level variables to the solver.
Definition: timetabler.cpp:50
Class for constraint adder.
Class for time tabler.
Definition: timetabler.h:44
Class for constraint encoder.
void parseFields(std::string file)
Parse the fields given in a file.
Definition: parser.cpp:19
void writeOutput(std::string)
Writes the generated time table to a CSV file.
Definition: timetabler.cpp:379
Timetabler * timetabler
Definition: main.cpp:90
void parseInput(std::string file)
Parses the input given in a file.
Definition: parser.cpp:129
void printResult(SolverStatus)
Prints the result of the problem.
Definition: timetabler.cpp:285
bool verify()
Verifies if the input is valid.
Definition: parser.cpp:246
void addVars()
Requests for variables to be added to the solver and stores the data.
Definition: parser.cpp:342
SolverStatus
Enum to store the solver status.
Definition: timetabler.h:19
SolverStatus solve()
Calls the solver to solve for the constraints.
Definition: timetabler.cpp:185
void parseCustomConstraints(std::string file, ConstraintEncoder *constraintEncoder, Timetabler *timetabler)
Parses custom constraints given in a file and adds them to the solver.
Class for parser.
Definition: parser.h:18