Repository navigation
Expand file tree
/
Copy pathnl-reader-example.cc
More file actions
232 lines (198 loc) · 7 KB
/
Copy pathnl-reader-example.cc
File metadata and controls
232 lines (198 loc) · 7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
// NL reader example
#include "mp/nl-reader.h"
#include <cstdlib>
#include <cstring>
#include <stdexcept>
#include <string>
namespace expr = mp::expr;
enum Expr {OTHER, CONST};
/// Count the number of divisions by non-constant expressions.
struct ExprCounter : mp::NullNLHandler<Expr> {
int num_divs;
ExprCounter() : num_divs(0) {}
Expr OnBinary(mp::expr::Kind kind, Expr, Expr rhs) {
if (kind == mp::expr::DIV && rhs != CONST)
++num_divs;
return OTHER;
}
Expr OnNumericConstant(double) { return CONST; }
};
/// Print problem dimensions: the number of constraints, variables and nonzeros
// (in constraints).
struct DimensionPrinter : mp::NullNLHandler<int> {
void OnHeader(const mp::NLHeader &h) {
fmt::print("Variables: {}\n", h.num_vars);
fmt::print("Constraints: {}\n", h.num_algebraic_cons);
fmt::print("Nonzeros: {}\n", h.num_con_nonzeros);
}
};
/// Print sparsity pattern of the objective and constraint gradients.
struct SparsityPrinter : mp::NullNLHandler<int> {
struct LinearObjHandler {
void AddTerm(int var_index, double) {
fmt::print(" {}\n", var_index);
}
};
typedef LinearObjHandler LinearConHandler;
LinearObjHandler OnLinearObjExpr(int obj_index, int) {
fmt::print("Objective {}:\n", obj_index);
return LinearObjHandler();
}
LinearConHandler OnLinearConExpr(int con_index, int) {
fmt::print("Constraint {}:\n", con_index);
return LinearConHandler();
}
};
/// Print objective or constraint expression in SSA-like form.
class ExprPrinter : public mp::NullNLHandler<std::string> {
private:
/// Next expression ID for SSA-like output.
int next_expr_id_;
/// Output for the currectly formatted expression.
fmt::MemoryWriter output_;
/// The formatted nonlinear expression ID.
int nonlinear_expr_id_;
/// Index of the objective to format or -1.
int obj_index_;
/// Index of the constraint to format or -1.
int con_index_;
/// Formats arguments and appends the result to ``output``.
template <typename... T>
std::string format(const char *format_str, const T &... args) {
std::string id = fmt::format("e{}", next_expr_id_++);
output_ << id << " = ";
output_.write(format_str, args...);
output_ << '\n';
return id;
}
/// Reset the writer for the next expression.
void reset() {
output_.clear();
next_expr_id_ = 0;
}
public:
ExprPrinter(int obj_index, int con_index)
: next_expr_id_(0), obj_index_(obj_index), con_index_(con_index) {}
std::string OnNumber(double value) {
return format("{}", value);
}
std::string OnVariableRef(int var_index) {
return fmt::format("x{}", var_index);
}
std::string OnUnary(expr::Kind kind, std::string arg) {
return kind == expr::MINUS ?
format("-{}", arg) : format("{}({})", expr::str(kind), arg);
}
std::string OnBinary(expr::Kind kind, std::string lhs, std::string rhs) {
const char *op = expr::str(kind);
return kind < expr::ATAN2 ?
format("{} {} {}", lhs, op, rhs) : format("{}({}, {})", op, lhs, rhs);
}
struct NumericArgHandler {
std::string args;
void AddArg(std::string arg) {
args = args.empty() ? arg : args + ", " + arg;
}
};
NumericArgHandler BeginSum(int) {
return NumericArgHandler();
}
std::string EndSum(NumericArgHandler handler) {
return format("sum({})", handler.args);
}
void OnObj(int obj_index, mp::obj::Type, std::string) {
if (obj_index == obj_index_) {
fmt::print("{}", output_.c_str());
nonlinear_expr_id_ = next_expr_id_ - 1;
}
reset();
}
void OnAlgebraicCon(int con_index, std::string) {
if (con_index == con_index_) {
fmt::print("{}", output_.c_str());
nonlinear_expr_id_ = next_expr_id_ - 1;
}
reset();
}
class LinearPartHandler {
private:
int num_terms; // The remaining number of terms to format.
int nonlinear_expr_id;
int obj_index;
char type; // Type: 'o' - objective, 'c' - constraint.
public:
explicit LinearPartHandler(int num_terms = 0, int nonlinear_expr_id = 0,
int obj_index = 0, char type = 'o')
: num_terms(num_terms), nonlinear_expr_id(nonlinear_expr_id),
obj_index(obj_index), type(type) {}
void AddTerm(int var_index, double coef) {
if (num_terms == 0) return;
--num_terms;
if (coef != 0) {
++nonlinear_expr_id;
fmt::print("e{} = ", nonlinear_expr_id);
if (nonlinear_expr_id != 0)
fmt::print("e{} + ", nonlinear_expr_id - 1);
fmt::print("x{} * {}\n", var_index, coef);
}
if (num_terms == 0)
fmt::print("{}{} = e{}\n", type, obj_index, nonlinear_expr_id);
}
};
typedef LinearPartHandler LinearObjHandler;
LinearObjHandler OnLinearObjExpr(int obj_index, int num_linear_terms) {
if (obj_index != obj_index_)
return LinearObjHandler();
if (num_linear_terms == 0)
fmt::print("o{} = e{}\n", obj_index, nonlinear_expr_id_);
return LinearObjHandler(num_linear_terms, nonlinear_expr_id_,
obj_index, 'o');
}
typedef LinearPartHandler LinearConHandler;
LinearConHandler OnLinearConExpr(int con_index, int num_linear_terms) {
if (con_index != con_index_)
return LinearConHandler();
if (num_linear_terms == 0)
fmt::print("c{} = e{}\n", con_index, nonlinear_expr_id_);
return LinearConHandler(num_linear_terms, nonlinear_expr_id_,
con_index, 'c');
}
};
int PrintUsage(const char *executable_name) {
fmt::print("Usage:\n");
fmt::print("{} (count|dimen|sparsity) <filename>\n", executable_name);
fmt::print(" count: count the number of divisions by non-constant "
"expressions\n");
fmt::print(" dimen: print problem dimensions\n");
fmt::print(" sparsity: print sparsity pattern\n");
fmt::print("{} (obj-expr|con-expr) <filename> <index>\n", executable_name);
fmt::print(" obj-expr: print objective expression\n");
fmt::print(" con-expr: print constraint expression\n");
return EXIT_FAILURE;
}
int main(int argc, char **argv) {
const char *executable_name = argv[0];
if (argc < 3)
return PrintUsage(executable_name);
const char *command = argv[1], *filename = argv[2];
if (std::strcmp(command, "count") == 0 && argc == 3) {
ExprCounter counter;
mp::ReadNLFile(filename, counter);
fmt::print("{} has {} division(s) by non-const\n",
filename, counter.num_divs);
} else if (std::strcmp(command, "dimen") == 0 && argc == 3) {
DimensionPrinter printer;
mp::ReadNLFile(filename, printer);
} else if (std::strcmp(command, "sparsity") == 0 && argc == 3) {
SparsityPrinter printer;
mp::ReadNLFile(filename, printer);
} else if (std::strcmp(command, "obj-expr") == 0 && argc == 4) {
ExprPrinter printer(std::atoi(argv[3]), -1);
mp::ReadNLFile(filename, printer);
} else if (std::strcmp(command, "con-expr") == 0 && argc == 4) {
ExprPrinter printer(-1, std::atoi(argv[3]));
mp::ReadNLFile(filename, printer);
} else {
return PrintUsage(executable_name);
}
}