1 /*
2 NL reader
3
4 NL is a format for representing optimization problems such as linear,
5 quadratic, nonlinear, complementarity and constraint programming problems
6 in discrete or continuous variables. It is described in the technical report
7 "Writing .nl Files" (http://www.cs.sandia.gov/~dmgay/nlwrite.pdf).
8
9 This is a complete reusable C++ implementation of an NL reader.
10
11 Usage:
12 // Read an NL file:
13 ReadNLFile(filename, handler);
14
15 // Read an NL string:
16 ReadNLString(string, handler);
17
18 where handler is an object that receives notifications of problem
19 components. See NLHandler for an example of a handler class.
20
21 Copyright (C) 2013 - 2016 AMPL Optimization Inc
22
23 Permission to use, copy, modify, and distribute this software and its
24 documentation for any purpose and without fee is hereby granted,
25 provided that the above copyright notice appear in all copies and that
26 both that the copyright notice and this permission notice and warranty
27 disclaimer appear in supporting documentation.
28
29 The author and AMPL Optimization Inc disclaim all warranties with
30 regard to this software, including all implied warranties of
31 merchantability and fitness. In no event shall the author be liable
32 for any special, indirect or consequential damages or any damages
33 whatsoever resulting from loss of use, data or profits, whether in an
34 action of contract, negligence or other tortious action, arising out
35 of or in connection with the use or performance of this software.
36
37 Author: Victor Zverovich
38 */
39
40 #ifndef MP_NL_READER_H_
41 #define MP_NL_READER_H_
42
43 #include "mp/common.h"
44 #include "mp/error.h"
45 #include "mp/nl.h"
46 #include "mp/os.h"
47
48 #include <algorithm>
49 #include <cctype>
50 #include <cstdlib>
51 #include <limits>
52 #include <string>
53
54 namespace mp {
55
56 using fmt::internal::MakeUnsigned;
57
58 /** A read error with location information. */
59 class ReadError : public Error {
60 private:
61 std::string filename_;
62 int line_;
63 int column_;
64
65 void init(fmt::CStringRef filename, int line, int column,
66 fmt::CStringRef format_str, fmt::ArgList args);
67
68 public:
69 /** Constructs the exception object. */
70 ReadError(fmt::CStringRef filename, int line, int column,
71 fmt::CStringRef format_str, fmt::ArgList args) {
72 init(filename, line, column, format_str, args);
73 }
74
75 /** Destructs the exception object. */
76 ~ReadError() throw() {}
77
78 /** Returns the name of the file where error occurred. */
79 const std::string &filename() const { return filename_; }
80
81 /** Returns the line number where error occurred, starting from 1. */
82 int line() const { return line_; }
83
84 /** Returns the column number where error occurred, starting from 1. */
85 int column() const { return column_; }
86
87 FMT_VARIADIC_(char, , ReadError, init,
88 fmt::CStringRef, int, int, fmt::CStringRef)
89 };
90
91 /** A read error with information about offset in a binary input. */
92 class BinaryReadError : public Error {
93 private:
94 std::string filename_;
95 std::size_t offset_;
96
97 public:
98 /** Constructs the exception object. */
99 BinaryReadError(
100 const std::string &filename, std::size_t offset, fmt::CStringRef message)
101 : Error(message), filename_(filename), offset_(offset) {}
102
103 /** Destructs the exception object. */
104 ~BinaryReadError() throw() {}
105
106 /** Returns the name of the file where error occurred. */
107 const std::string &filename() const { return filename_; }
108
109 /** Returns the offset in chars to the error location. */
110 std::size_t offset() const { return offset_; }
111 };
112
113 enum {
114 /** Maximum number of options reserved for AMPL use in NL and SOL formats. */
115 MAX_AMPL_OPTIONS = 9
116 };
117
118 namespace arith {
119
120 /** Floating-point arithmetic kind. */
121 enum Kind {
122
123 /** Unknown floating-point arithmetic. */
124 UNKNOWN = 0,
125
126 /**
127 \rst
128 Standard `IEEE-754 floating point
129 <http://en.wikipedia.org/wiki/IEEE_floating_point>`_ - little endian.
130 \endrst
131 */
132 IEEE_LITTLE_ENDIAN = 1,
133
134 /** Standard IEEE-754 floating point - big endian. */
135 IEEE_BIG_ENDIAN = 2,
136
137 /**
138 \rst
139 `IBM floating point
140 <http://en.wikipedia.org/wiki/IBM_Floating_Point_Architecture>`_.
141 \endrst
142 */
143 IBM = 3,
144
145 /** VAX floating point (legacy). */
146 VAX = 4,
147
148 /** Cray floating point. */
149 CRAY = 5,
150
151 /** Last floating point. */
152 LAST = CRAY
153 };
154
155 // Returns floating-point arithmetic kind used on the current system.
156 Kind GetKind();
157
158 inline bool IsIEEE(arith::Kind k) {
159 return k == IEEE_LITTLE_ENDIAN || k == IEEE_BIG_ENDIAN;
160 }
161 } // namespace arith
162
163 /**
164 \rst
165 An NL `header <http://en.wikipedia.org/wiki/Header_(computing)>`_
166 which contains information about problem dimensions, such as the number of
167 variables and constraints, and the input format.
168
169 Base class: `mp::ProblemInfo`
170 \endrst
171 */
172 struct NLHeader : ProblemInfo {
173 /** Input/output format */
174 enum Format {
175 /**
176 Text format. The text format is fully portable meaning that an .nl file
177 can be written on a machine of one architecture and then read on a
178 machine of a different architecture.
179 */
180 TEXT = 0,
181
182 /**
183 Binary format. The binary format is not generally portable and should
184 normally be used on a single machine.
185 */
186 BINARY = 1
187 };
188
189 /** Input/output format. */
190 Format format;
191
192 /** The number of options reserved for AMPL use. */
193 int num_ampl_options;
194
195 /**
196 Values of options reserved for AMPL use. Leave the default values if not
197 using AMPL.
198 */
199 int ampl_options[MAX_AMPL_OPTIONS];
200
201 /**
202 Extra info for writing a solution reserved for AMPL use. Leave the default
203 value if not using AMPL.
204 */
205 double ampl_vbtol;
206
207 /**
208 \rst
209 Floating-point arithmetic kind used with binary format to check
210 if an .nl file is written using a compatible representation of
211 floating-point numbers. It is not used with the text format and normally
212 set to `mp::arith::UNKNOWN` there.
213 \endrst
214 */
215 arith::Kind arith_kind;
216
217 /** Flags. */
218 enum {
219 /** Flag that specifies whether to write output suffixes to a .sol file. */
220 WANT_OUTPUT_SUFFIXES = 1
221 };
222
223 /**
224 \rst
225 Flags. Can be either 0 or `mp::NLHeader::WANT_OUTPUT_SUFFIXES`.
226 \endrst
227 */
228 int flags;
229
230 NLHeader()
231 : ProblemInfo(), format(TEXT), num_ampl_options(0), ampl_vbtol(0),
232 arith_kind(arith::UNKNOWN), flags(0) {
233 std::fill(ampl_options, ampl_options + MAX_AMPL_OPTIONS, 0);
234 }
235 };
236
237 /** Writes NLHeader in the NL format. */
238 fmt::Writer &operator<<(fmt::Writer &w, const NLHeader &h);
239
240 /**
241 \rst
242 An NL handler.
243
244 `~mp::NLHandler` can be used as a base class for other handlers. Subclasses
245 only need to redefine methods that handle constructs they are interested
246 in and, possibly, the types used by these methods.
247
248 *Impl* is a type derived from `~mp::NLHandler` that will receive notifications
249 of unhandled constructs via `~mp::NLHandler::OnUnhandled`.
250
251 *ExprType* is a return type of expression handler methods such as
252 `~mp::NLHandler::OnUnary` useful for building expression objects. If not used
253 it can be any default-constructible type.
254 \endrst
255 */
256 template <typename Impl, typename ExprType>
257 class NLHandler {
258 public:
259 /** Destroys the object. */
260 virtual ~NLHandler() {}
261
262 /** An expression type. */
263 typedef ExprType Expr;
264
265 /**
266 \rst
267 .. |Expr| replace:: `Expr <mp::NLHandler::Expr>`
268
269 A numeric expression type.
270 It is a typedef of |Expr| but subclasses may define it as a different type
271 convertible to |Expr|.
272 \endrst
273 */
274 typedef Expr NumericExpr;
275
276 /**
277 \rst
278 A logical expression type.
279 It is a typedef of |Expr| but subclasses may define it as a different type
280 convertible to |Expr|.
281 \endrst
282 */
283 typedef Expr LogicalExpr;
284
285 /**
286 \rst
287 A count expression type.
288 It is a typedef of |Expr| but subclasses may define it as a different type
289 convertible to `NumericExpr <mp::NLHandler::NumericExpr>`.
290 \endrst
291 */
292 typedef Expr CountExpr;
293
294 /**
295 \rst
296 A reference expression type.
297 It is a typedef of |Expr| but subclasses may define it as a different type
298 convertible to `NumericExpr <mp::NLHandler::NumericExpr>`.
299 \endrst
300 */
301 typedef Expr Reference;
302
303 /**
304 Receives notification of an unhandled construct of the given kind.
305 Throws `UnsupportedError`.
306 */
307 void OnUnhandled(const char *kind) {
308 throw MakeUnsupportedError(kind);
309 }
310
311 /** Receives notification of an NL header. */
312 void OnHeader(const NLHeader &h) {
313 internal::Unused(&h);
314 MP_DISPATCH(OnUnhandled("NL header"));
315 }
316
317 /**
318 \rst
319 Returns true if the objective with index *obj_index* should be handled.
320 \endrst
321 */
322 bool NeedObj(int obj_index) const {
323 internal::Unused(obj_index);
324 return true;
325 }
326
327 /**
328 \rst
329 Returns final objective index
330 (e.g., returns 0 if objno>0 and multiobj=0)
331 \endrst
332 */
333 int resulting_obj_index(int obj_index) const { return obj_index; }
334
335 /**
336 Receives notification of an objective type and the nonlinear part of
337 an objective expression.
338 */
339 void OnObj(int index, obj::Type type, NumericExpr expr) {
340 internal::Unused(index, type, &expr);
341 MP_DISPATCH(OnUnhandled("objective"));
342 }
343
344 /**
345 Receives notification of the nonlinear part of an algebraic constraint
346 expression.
347 */
348 void OnAlgebraicCon(int index, NumericExpr expr) {
349 internal::Unused(index, &expr);
350 MP_DISPATCH(OnUnhandled("nonlinear constraint"));
351 }
352
353 /** Receives notification of a logical constraint expression. */
354 void OnLogicalCon(int index, LogicalExpr expr) {
355 internal::Unused(index, &expr);
356 MP_DISPATCH(OnUnhandled("logical constraint"));
357 }
358
359 /**
360 A class (struct) that receives notifications of terms in the linear part
361 of a common expression.
362 */
363 struct LinearExprHandler {
364 /** Receives notification of a term in the linear expression. */
365 void AddTerm(int var_index, double coef) {
366 internal::Unused(var_index, coef);
367 }
368 };
369
370 /**
371 Receives notification of the beginning of a common expression
372 (defined variable).
373 */
374 LinearExprHandler BeginCommonExpr(int index, int num_linear_terms) {
375 internal::Unused(index, num_linear_terms);
376 MP_DISPATCH(OnUnhandled("common expression"));
377 return LinearExprHandler();
378 }
379
380 /** Receives notification of the end of a common expression. */
381 void EndCommonExpr(int index, NumericExpr expr, int position) {
382 internal::Unused(index, &expr, position);
383 MP_DISPATCH(OnUnhandled("common expression"));
384 }
385
386 /**
387 \rst
388 Receives notification of a complementarity relation
389 ``var_lb <= x <= var_ub complements con_lb <= body <= con_ub``, where ``x``
390 is the variable at index *var_index* and ``body`` is the constraint body.
391 *info* gives the constraint bounds.
392 \endrst
393 */
394 void OnComplementarity(int con_index, int var_index, ComplInfo info) {
395 internal::Unused(con_index, var_index, &info);
396 MP_DISPATCH(OnUnhandled("complementarity constraint"));
397 }
398
399 /**
400 A typedef of a class that receives notifications of terms in the linear
401 part of an objective expression.
402 */
403 typedef LinearExprHandler LinearObjHandler;
404
405 /** Receives notification of the linear part of an objective expression. */
406 LinearObjHandler OnLinearObjExpr(int obj_index, int num_linear_terms) {
407 internal::Unused(obj_index, num_linear_terms);
408 MP_DISPATCH(OnUnhandled("linear objective"));
409 return LinearObjHandler();
410 }
411
412 /**
413 A typedef of a class that receives notifications of terms in the linear
414 part of a constraint expression.
415 */
416 typedef LinearExprHandler LinearConHandler;
417
418 /** Receives notification of the linear part of a constraint expression. */
419 LinearConHandler OnLinearConExpr(int con_index, int num_linear_terms) {
420 internal::Unused(con_index, num_linear_terms);
421 MP_DISPATCH(OnUnhandled("linear constraint"));
422 return LinearConHandler();
423 }
424
425 /** Receives notification of the linear part of a common expression. */
426 LinearExprHandler OnLinearCommonExpr(int expr_index, int num_linear_terms) {
427 internal::Unused(expr_index, num_linear_terms);
428 MP_DISPATCH(OnUnhandled("linear common expression"));
429 return LinearExprHandler();
430 }
431
432 /** Receives notification of variable bounds. */
433 void OnVarBounds(int index, double lb, double ub) {
434 internal::Unused(index, lb, ub);
435 MP_DISPATCH(OnUnhandled("variable bounds"));
436 }
437
438 /** Receives notification of constraint bounds (ranges). */
439 void OnConBounds(int index, double lb, double ub) {
440 internal::Unused(index, lb, ub);
441 MP_DISPATCH(OnUnhandled("constraint bounds"));
442 }
443
444 /** Receives notification of the initial value for a variable. */
445 void OnInitialValue(int var_index, double value) {
446 internal::Unused(var_index, value);
447 MP_DISPATCH(OnUnhandled("initial value"));
448 }
449
450 /** Receives notification of the initial value for a dual variable. */
451 void OnInitialDualValue(int con_index, double value) {
452 internal::Unused(con_index, value);
453 MP_DISPATCH(OnUnhandled("initial dual value"));
454 }
455
456 /** A class (struct) that receives notifications of Jacobian column sizes. */
457 struct ColumnSizeHandler {
458 /** Receives notification of a Jacobian column size. */
459 void Add(int size) { internal::Unused(size); }
460 };
461
462 /** Receives notification of Jacobian column sizes. */
463 ColumnSizeHandler OnColumnSizes() {
464 MP_DISPATCH(OnUnhandled("column sizes"));
465 return ColumnSizeHandler();
466 }
467
468 /**
469 \rst
470 Receives notification of a function.
471 The *name* argument is a function name and it is not null-terminated.
472 \endrst
473 */
474 void OnFunction(int index, fmt::StringRef name,
475 int num_args, func::Type type) {
476 internal::Unused(index, &name, num_args, type);
477 MP_DISPATCH(OnUnhandled("function"));
478 }
479
480 /** A class (struct) that receives notifications of integer suffix values. */
481 struct IntSuffixHandler {
482 /** Receives notification of a suffix value. */
483 void SetValue(int index, int value) { internal::Unused(index, value); }
484 };
485
486 /**
487 \rst
488 Receives notification of an integer suffix.
489 The *name* argument is a suffix name and it is not null-terminated.
490 *kind* specifies the suffix kind.
491 \endrst
492 */
493 IntSuffixHandler OnIntSuffix(fmt::StringRef name, suf::Kind kind,
494 int num_values) {
495 internal::Unused(&name, kind, num_values);
496 MP_DISPATCH(OnUnhandled("integer suffix"));
497 return IntSuffixHandler();
498 }
499
500 /** A class (struct) that receives notifications of double suffix values. */
501 struct DblSuffixHandler {
502 /** Receives notification of a suffix value. */
503 void SetValue(int index, double value) { internal::Unused(index, value); }
504 };
505
506 /**
507 \rst
508 Receives notification of a double suffix.
509 The *name* argument is a suffix name and it is not null-terminated.
510 *kind* specifies the suffix kind.
511 \endrst
512 */
513 DblSuffixHandler OnDblSuffix(fmt::StringRef name, suf::Kind kind,
514 int num_values) {
515 internal::Unused(&name, kind, num_values);
516 MP_DISPATCH(OnUnhandled("double suffix"));
517 return DblSuffixHandler();
518 }
519
520 /**
521 \rst
522 A class (struct) that receives notifications of expression arguments.
523 All argument handlers in `mp::NLHandler` are typedefs of this class, but
524 subclasses of `mp::NLHandler` may define them as different classes.
525 \endrst
526 */
527 struct ArgHandler {
528 /** Receives notification of an argument. */
529 void AddArg(Expr arg) { internal::Unused(&arg); }
530 };
531
532 /**
533 \rst
534 A typedef of a class that receives notifications of `numeric
535 <mp::expr::FIRST_NUMERIC>` arguments.
536 \endrst
537 */
538 typedef ArgHandler NumericArgHandler;
539
540 /**
541 \rst
542 A typedef of a class that receives notifications of `vararg expression
543 <mp::expr::FIRST_VARARG>` arguments.
544 \endrst
545 */
546 typedef ArgHandler VarArgHandler;
547
548 /**
549 \rst
550 A typedef of a class that receives notifications of `call expression
551 <mp::expr::CALL>` arguments.
552 \endrst
553 */
554 typedef ArgHandler CallArgHandler;
555
556 /**
557 \rst
558 A typedef of a class that receives notifications of `numberof expression
559 <mp::expr::NUMBEROF>` arguments.
560 \endrst
561 */
562 typedef ArgHandler NumberOfArgHandler;
563
564 /**
565 \rst
566 A typedef of a class that receives notifications of `count expression
567 <mp::expr::COUNT>` arguments.
568 \endrst
569 */
570 typedef ArgHandler CountArgHandler;
571
572 /**
573 \rst
574 A typedef of a class that receives notifications of `logical
575 <mp::expr::FIRST_LOGICAL>` arguments.
576 \endrst
577 */
578 typedef ArgHandler LogicalArgHandler;
579
580 /**
581 \rst
582 A typedef of a class that receives notifications of `pairwise expression
583 <mp::expr::FIRST_PAIRWISE>` arguments.
584 \endrst
585 */
586 typedef ArgHandler PairwiseArgHandler;
587
588 /**
589 \rst
590 A typedef of a class that receives notifications of symbolic
591 (`numeric <mp::expr::FIRST_NUMERIC>` or `string <mp::expr::STRING>`)
592 arguments.
593 \endrst
594 */
595 typedef ArgHandler SymbolicArgHandler;
596
597 /**
598 \rst
599 Receives notification of a `number <mp::expr::FIRST_NUMERIC>` in a
600 nonlinear expression.
601 \endrst
602 */
603 NumericExpr OnNumber(double value) {
604 internal::Unused(value);
605 MP_DISPATCH(OnUnhandled("number"));
606 return NumericExpr();
607 }
608
609 /**
610 \rst
611 Receives notification of a `variable reference <mp::expr::FIRST_REFERENCE>`.
612 \endrst
613 */
614 Reference OnVariableRef(int var_index) {
615 internal::Unused(var_index);
616 MP_DISPATCH(OnUnhandled("variable reference"));
617 return Reference();
618 }
619
620 /**
621 \rst
622 Receives notification of a `common expression <mp::expr::COMMON_EXPR>`
623 (defined variable) reference.
624 \endrst
625 */
626 Reference OnCommonExprRef(int expr_index) {
627 internal::Unused(expr_index);
628 MP_DISPATCH(OnUnhandled("common expression reference"));
629 return Reference();
630 }
631
632 /**
633 \rst
634 Receives notification of a `unary expression <mp::expr::FIRST_UNARY>`.
635 \endrst
636 */
637 NumericExpr OnUnary(expr::Kind kind, NumericExpr arg) {
638 internal::Unused(kind, &arg);
639 MP_DISPATCH(OnUnhandled("unary expression"));
640 return NumericExpr();
641 }
642
643 /**
644 \rst
645 Receives notification of a `binary expression <mp::expr::FIRST_BINARY>`.
646 \endrst
647 */
648 NumericExpr OnBinary(expr::Kind kind, NumericExpr lhs, NumericExpr rhs) {
649 internal::Unused(kind, &lhs, &rhs);
650 MP_DISPATCH(OnUnhandled("binary expression"));
651 return NumericExpr();
652 }
653
654 /**
655 \rst
656 Receives notification of an `if expression <mp::expr::IF>`.
657 \endrst
658 */
659 NumericExpr OnIf(LogicalExpr condition,
660 NumericExpr then_expr, NumericExpr else_expr) {
661 internal::Unused(&condition, &then_expr, &else_expr);
662 MP_DISPATCH(OnUnhandled("if expression"));
663 return NumericExpr();
664 }
665
666 /**
667 \rst
668 A class (struct) that receives notifications of slopes and breakpoints in a
669 `piecewise-linear term <mp::expr::PLTERM>`.
670 \endrst
671 */
672 struct PLTermHandler {
673 /** Receives notification of a slope. */
674 void AddSlope(double slope) { internal::Unused(slope); }
675
676 /** Receives notification of a breakpoint. */
677 void AddBreakpoint(double breakpoint) { internal::Unused(breakpoint); }
678 };
679
680 /**
681 \rst
682 Receives notification of the beginning of a `piecewise-linear term
683 <mp::expr::PLTERM>`.
684 \endrst
685 */
686 PLTermHandler BeginPLTerm(int num_breakpoints) {
687 internal::Unused(num_breakpoints);
688 MP_DISPATCH(OnUnhandled("piecewise-linear term"));
689 return PLTermHandler();
690 }
691
692 /**
693 \rst
694 Receives notification of the end of a `piecewise-linear term
695 <mp::expr::PLTERM>`.
696
697 *arg*: argument that is a variable or a common expression reference.
698 \endrst
699 */
700 NumericExpr EndPLTerm(PLTermHandler handler, Reference arg) {
701 internal::Unused(&handler, &arg);
702 MP_DISPATCH(OnUnhandled("piecewise-linear term"));
703 return NumericExpr();
704 }
705
706 /**
707 \rst
708 Receives notification of the beginning of a `call expression
709 <mp::expr::CALL>`.
710 \endrst
711 */
712 CallArgHandler BeginCall(int func_index, int num_args) {
713 internal::Unused(func_index, num_args);
714 MP_DISPATCH(OnUnhandled("call expression"));
715 return CallArgHandler();
716 }
717
718 /**
719 \rst
720 Receives notification of the end of a `call expression <mp::expr::CALL>`.
721 \endrst
722 */
723 NumericExpr EndCall(CallArgHandler handler) {
724 internal::Unused(handler);
725 MP_DISPATCH(OnUnhandled("call expression"));
726 return NumericExpr();
727 }
728
729 /**
730 \rst
731 Receives notification of the beginning of a `vararg expression
732 <mp::expr::FIRST_VARARG>`.
733 \endrst
734 */
735 VarArgHandler BeginVarArg(expr::Kind kind, int num_args) {
736 internal::Unused(kind, num_args);
737 MP_DISPATCH(OnUnhandled("vararg expression"));
738 return NumericArgHandler();
739 }
740
741 /**
742 \rst
743 Receives notification of the end of a `vararg expression
744 <mp::expr::FIRST_VARARG>`.
745 \endrst
746 */
747 NumericExpr EndVarArg(VarArgHandler handler) {
748 internal::Unused(handler);
749 MP_DISPATCH(OnUnhandled("vararg expression"));
750 return NumericExpr();
751 }
752
753 /**
754 \rst
755 Receives notification of the beginning of a `summation <mp::expr::SUM>`.
756 \endrst
757 */
758 NumericArgHandler BeginSum(int num_args) {
759 internal::Unused(num_args);
760 MP_DISPATCH(OnUnhandled("summation"));
761 return NumericArgHandler();
762 }
763
764 /**
765 \rst
766 Receives notification of the end of a `summation <mp::expr::SUM>`.
767 \endrst
768 */
769 NumericExpr EndSum(NumericArgHandler handler) {
770 internal::Unused(handler);
771 MP_DISPATCH(OnUnhandled("summation"));
772 return NumericExpr();
773 }
774
775 /**
776 \rst
777 Receives notification of the beginning of a `count expression
778 <mp::expr::COUNT>`.
779 \endrst
780 */
781 CountArgHandler BeginCount(int num_args) {
782 internal::Unused(num_args);
783 MP_DISPATCH(OnUnhandled("count expression"));
784 return CountArgHandler();
785 }
786
787 /**
788 \rst
789 Receives notification of the end of a `count expression <mp::expr::COUNT>`.
790 \endrst
791 */
792 CountExpr EndCount(CountArgHandler handler) {
793 internal::Unused(handler);
794 MP_DISPATCH(OnUnhandled("count expression"));
795 return NumericExpr();
796 }
797
798 /**
799 \rst
800 Receives notification of the beginning of a `numberof expression
801 <mp::expr::NUMBEROF>`.
802 \endrst
803 */
804 NumberOfArgHandler BeginNumberOf(int num_args, NumericExpr arg0) {
805 internal::Unused(num_args, &arg0);
806 MP_DISPATCH(OnUnhandled("numberof expression"));
807 return NumberOfArgHandler();
808 }
809
810 /**
811 \rst
812 Receives notification of the end of a `numberof expression
813 <mp::expr::NUMBEROF>`.
814 \endrst
815 */
816 NumericExpr EndNumberOf(NumberOfArgHandler handler) {
817 internal::Unused(handler);
818 MP_DISPATCH(OnUnhandled("numberof expression"));
819 return NumericExpr();
820 }
821
822 /**
823 \rst
824 Receives notification of the beginning of a `symbolic numberof
825 expression <mp::expr::NUMBEROF_SYM>`.
826 \endrst
827 */
828 SymbolicArgHandler BeginSymbolicNumberOf(int num_args, Expr arg0) {
829 internal::Unused(num_args, &arg0);
830 MP_DISPATCH(OnUnhandled("symbolic numberof expression"));
831 return SymbolicArgHandler();
832 }
833
834 /**
835 \rst
836 Receives notification of the end of a `symbolic numberof expression
837 <mp::expr::NUMBEROF_SYM>`.
838 \endrst
839 */
840 NumericExpr EndSymbolicNumberOf(SymbolicArgHandler handler) {
841 internal::Unused(handler);
842 MP_DISPATCH(OnUnhandled("symbolic numberof expression"));
843 return NumericExpr();
844 }
845
846 /**
847 \rst
848 Receives notification of a `Boolean value <mp::expr::BOOL>`.
849 \endrst
850 */
851 LogicalExpr OnBool(bool value) {
852 internal::Unused(value);
853 MP_DISPATCH(OnUnhandled("bool"));
854 return LogicalExpr();
855 }
856
857 /**
858 \rst
859 Receives notification of a `logical not <mp::expr::NOT>`.
860 \endrst
861 */
862 LogicalExpr OnNot(LogicalExpr arg) {
863 internal::Unused(&arg);
864 MP_DISPATCH(OnUnhandled("logical not"));
865 return LogicalExpr();
866 }
867
868 /**
869 \rst
870 Receives notification of a `binary logical expression
871 <mp::expr::FIRST_BINARY_LOGICAL>`.
872 \endrst
873 */
874 LogicalExpr OnBinaryLogical(
875 expr::Kind kind, LogicalExpr lhs, LogicalExpr rhs) {
876 internal::Unused(kind, &lhs, &rhs);
877 MP_DISPATCH(OnUnhandled("binary logical expression"));
878 return LogicalExpr();
879 }
880
881 /**
882 \rst
883 Receives notification of a `relational expression
884 <mp::expr::FIRST_RELATIONAL>`.
885 \endrst
886 */
887 LogicalExpr OnRelational(expr::Kind kind, NumericExpr lhs, NumericExpr rhs) {
888 internal::Unused(kind, &lhs, &rhs);
889 MP_DISPATCH(OnUnhandled("relational expression"));
890 return LogicalExpr();
891 }
892
893 /**
894 \rst
895 Receives notification of a `logical count expression
896 <mp::expr::FIRST_LOGICAL_COUNT>`.
897 \endrst
898 */
899 LogicalExpr OnLogicalCount(expr::Kind kind, NumericExpr lhs, CountExpr rhs) {
900 internal::Unused(kind, &lhs, &rhs);
901 MP_DISPATCH(OnUnhandled("logical count expression"));
902 return LogicalExpr();
903 }
904
905 /**
906 \rst
907 Receives notification of an `implication expression
908 <mp::expr::IMPLICATION>`.
909 \endrst
910 */
911 LogicalExpr OnImplication(
912 LogicalExpr condition, LogicalExpr then_expr, LogicalExpr else_expr) {
913 internal::Unused(&condition, &then_expr, &else_expr);
914 MP_DISPATCH(OnUnhandled("implication expression"));
915 return LogicalExpr();
916 }
917
918 /**
919 \rst
920 Receives notification of the beginning of an `iterated logical
921 expression <mp::expr::FIRST_ITERATED_LOGICAL>`.
922 \endrst
923 */
924 LogicalArgHandler BeginIteratedLogical(expr::Kind kind, int num_args) {
925 internal::Unused(kind, num_args);
926 MP_DISPATCH(OnUnhandled("iterated logical expression"));
927 return LogicalArgHandler();
928 }
929
930 /**
931 \rst
932 Receives notification of the end of an `iterated logical expression
933 <mp::expr::FIRST_ITERATED_LOGICAL>`.
934 \endrst
935 */
936 LogicalExpr EndIteratedLogical(LogicalArgHandler handler) {
937 internal::Unused(handler);
938 MP_DISPATCH(OnUnhandled("iterated logical expression"));
939 return LogicalExpr();
940 }
941
942 /**
943 \rst
944 Receives notification of the beginning of a `pairwise expression
945 <mp::expr::FIRST_PAIRWISE>`.
946 \endrst
947 */
948 PairwiseArgHandler BeginPairwise(expr::Kind kind, int num_args) {
949 internal::Unused(kind, num_args);
950 MP_DISPATCH(OnUnhandled("pairwise expression"));
951 return PairwiseArgHandler();
952 }
953
954 /**
955 \rst
956 Receives notification of the end of a `pairwise expression
957 <mp::expr::FIRST_PAIRWISE>`.
958 \endrst
959 */
960 LogicalExpr EndPairwise(PairwiseArgHandler handler) {
961 internal::Unused(handler);
962 MP_DISPATCH(OnUnhandled("pairwise expression"));
963 return LogicalExpr();
964 }
965
966 /**
967 \rst
968 Receives notification of a `string <mp::expr::STRING>`.
969 The *value* argument is a string value and it is not null-terminated.
970 \endrst
971 */
972 Expr OnString(fmt::StringRef value) {
973 internal::Unused(&value);
974 MP_DISPATCH(OnUnhandled("string"));
975 return Expr();
976 }
977
978 /**
979 \rst
980 Receives notification of a `symbolic if expression <mp::expr::IFSYM>`.
981 \endrst
982 */
983 Expr OnSymbolicIf(LogicalExpr condition, Expr then_expr, Expr else_expr) {
984 internal::Unused(&condition, &then_expr, &else_expr);
985 MP_DISPATCH(OnUnhandled("symbolic if expression"));
986 return Expr();
987 }
988
989 /** Receives notification of the end of the input. */
990 void EndInput() {}
991 };
992
993 /**
994 \rst
995 An NL handler that ignores all input.
996
997 `~mp::NullNLHandler` can be used as a base class when only a subset of
998 constructs needs to be handled. Unhandled constructs will be ignored, not
999 reported.
1000
1001 *ExprType* is a return type of expression handler methods such as
1002 `~mp::NLHandler::OnUnary` useful for building expression objects. If not used
1003 it can be any default-constructible type.
1004 \endrst
1005 */
1006 template <typename ExprType>
1007 class NullNLHandler : public NLHandler<NullNLHandler<ExprType>, ExprType> {
1008 public:
1009 /** Receives notification of an unhandled construct and ignores it. */
1010 void OnUnhandled(const char *) {}
1011 };
1012
1013 namespace internal {
1014
1015 class ReaderBase {
1016 protected:
1017 const char *ptr_, *start_, *end_;
1018 const char *token_; // start of the current token
1019 std::string name_;
1020
1021 ~ReaderBase() {}
1022
1023 public:
1024 ReaderBase(NLStringRef data, fmt::CStringRef name);
1025
1026 char ReadChar() {
1027 token_ = ptr_;
1028 return *ptr_++;
1029 }
1030
(1) Event side_effect_free_fn: |
This function only appears useful for its return value. |
1031 const char *ptr() const { return ptr_; }
1032 void set_ptr(const char *ptr) { token_ = ptr_ = ptr; }
1033
1034 bool IsEOF(const char *ptr) const { return ptr == end_ + 1; }
1035 bool IsEOF() const { return IsEOF(ptr_); }
1036 };
1037
1038 #ifdef FMT_LOCALE
1039 typedef fmt::Locale Locale;
1040 #else
1041 # warning "Parsing is locale-dependent"
1042 struct Locale {
1043 double strtod(const char *&str) const {
1044 char *end = 0;
1045 double result = std::strtod(str, &end);
1046 str = end;
1047 return result;
1048 }
1049 };
1050 #endif
1051
1052 template <typename Locale = Locale>
1053 class TextReader : public ReaderBase {
1054 private:
1055 const char *line_start_;
1056 int line_;
1057
1058 class CopyableLocale : public Locale {
1059 public:
1060 CopyableLocale() {}
1061 // All Locale objects refer to the "C" locale, so no need to copy.
1062 CopyableLocale(const CopyableLocale &) : Locale() {}
1063 CopyableLocale &operator=(const CopyableLocale &) { return *this; }
1064 };
1065 CopyableLocale locale_;
1066
1067 // Reads an integer without a sign.
1068 // Int: signed or unsigned integer type.
1069 template <typename Int>
1070 bool ReadIntWithoutSign(Int& value) {
1071 char c = *ptr_;
1072 if (c < '0' || c > '9')
1073 return false;
1074 typedef typename MakeUnsigned<Int>::Type UInt;
1075 UInt result = 0;
1076 do {
1077 UInt new_result = result * 10 + (c - '0');
1078 if (new_result < result)
1079 ReportError("number is too big");
1080 result = new_result;
1081 c = *++ptr_;
1082 } while (c >= '0' && c <= '9');
1083 UInt max = std::numeric_limits<Int>::max();
1084 if (result > max)
1085 ReportError("number is too big");
1086 value = result;
1087 return true;
1088 }
1089
1090 template <typename Int>
1091 bool DoReadOptionalInt(Int &value) {
1092 SkipSpace();
1093 char sign = *ptr_;
1094 if (sign == '+' || sign == '-')
1095 ++ptr_;
1096 typedef typename MakeUnsigned<Int>::Type UInt;
1097 UInt result = 0;
1098 if (!ReadIntWithoutSign<UInt>(result))
1099 return false;
1100 UInt max = std::numeric_limits<Int>::max();
1101 if (result > max && !(sign == '-' && result == max + 1))
1102 ReportError("number is too big");
1103 value = sign != '-' ? result : 0 - result;
1104 return true;
1105 }
1106
1107 // Reads a nonnegative integer and checks that adding it to accumulator
1108 // doesn't overflow.
1109 int ReadUInt(int &accumulator) {
1110 int value = ReadUInt();
1111 if (accumulator > std::numeric_limits<int>::max() - value)
1112 ReportError("integer overflow");
1113 accumulator += value;
1114 return value;
1115 }
1116
1117 template <typename Int>
1118 Int ReadUInt() {
1119 SkipSpace();
1120 Int value = 0;
1121 if (!ReadIntWithoutSign(value))
1122 ReportError("expected unsigned integer");
1123 return value;
1124 }
1125
1126 bool ReadOptionalInt(int &value) { return DoReadOptionalInt(value); }
1127
1128 bool ReadOptionalUInt(int &value) {
1129 SkipSpace();
1130 return ReadIntWithoutSign(value);
1131 }
1132
1133 bool ReadOptionalDouble(double &value);
1134
1135 void DoReportError(
1136 const char *loc, fmt::CStringRef format_str,
1137 const fmt::ArgList &args = fmt::ArgList());
1138
1139 void SkipSpace() {
1140 while (std::isspace(*ptr_) && *ptr_ != '\n')
1141 ++ptr_;
1142 token_ = ptr_;
1143 }
1144
1145 public:
1146 TextReader(NLStringRef data, fmt::CStringRef name);
1147
1148 Locale &locale() { return locale_; }
1149
1150 void ReportError(fmt::CStringRef format_str, const fmt::ArgList &args) {
1151 DoReportError(token_, format_str, args);
1152 }
1153 FMT_VARIADIC(void, ReportError, fmt::CStringRef)
1154
1155 void ReadTillEndOfLine() {
1156 while (char c = *ptr_) {
1157 ++ptr_;
1158 if (c == '\n') {
1159 line_start_ = ptr_;
1160 ++line_;
1161 return;
1162 }
1163 }
1164 DoReportError(ptr_, "expected newline");
1165 }
1166
1167 template <typename Int>
1168 Int ReadInt() {
1169 Int value = 0;
1170 if (!DoReadOptionalInt(value))
1171 ReportError("expected integer");
1172 return value;
1173 }
1174
1175 int ReadUInt() { return ReadUInt<int>(); }
1176
1177 double ReadDouble() {
1178 SkipSpace();
1179 const char *start = ptr_;
1180 double value = 0;
1181 if (*ptr_ != '\n')
1182 value = locale_.strtod(ptr_);
1183 if (ptr_ == start)
1184 ReportError("expected double");
1185 return value;
1186 }
1187
1188 fmt::StringRef ReadString();
1189
1190 // Reads a function or suffix name.
1191 fmt::StringRef ReadName();
1192
1193 // Reads an .nl file header. The header is always in text format, so this
1194 // function doesn't have a counterpart in BinaryReader.
1195 void ReadHeader(NLHeader &header);
1196 };
1197
1198 // Converter that doesn't change the input.
1199 class IdentityConverter {
1200 public:
1201 template <typename T>
1202 T Convert(T value) { return value; }
1203 };
1204
1205 // Converter that changes the input endianness.
1206 class EndiannessConverter {
1207 private:
1208 void Convert(char *data, std::size_t size) {
1209 std::reverse(data, data + size);
1210 }
1211
1212 public:
1213 template <typename T>
1214 T Convert(T value) {
1215 Convert(reinterpret_cast<char*>(&value), sizeof(T));
1216 return value;
1217 }
1218 };
1219
1220 class BinaryReaderBase : public ReaderBase {
1221 protected:
1222 explicit BinaryReaderBase(const ReaderBase &base) : ReaderBase(base) {}
1223
1224 // Reads length chars.
1225 const char *Read(int length) {
1226 if (end_ - ptr_ < length) {
1227 token_ = end_;
1228 ReportError("unexpected end of file");
1229 }
1230 const char *start = ptr_;
1231 ptr_ += length;
1232 return start;
1233 }
1234
1235 public:
1236 void ReportError(fmt::CStringRef format_str, const fmt::ArgList &args);
1237 FMT_VARIADIC(void, ReportError, fmt::CStringRef)
1238
1239 void ReadTillEndOfLine() {
1240 // Do nothing.
1241 }
1242 };
1243
1244 // Binary reader.
1245 template <typename InputConverter = IdentityConverter>
1246 class BinaryReader : private InputConverter, public BinaryReaderBase {
1247 public:
1248 explicit BinaryReader(const ReaderBase &base) : BinaryReaderBase(base) {}
1249
1250 template <typename Int>
1251 Int ReadInt() {
1252 token_ = ptr_;
1253 Int val;
1254 memcpy(&val, Read(sizeof(Int)), sizeof(Int));
1255 return this->Convert(val);
1256 }
1257
1258 int ReadUInt() {
1259 int value = ReadInt<int>();
1260 if (value < 0)
1261 ReportError("expected unsigned integer");
1262 return value;
1263 }
1264
1265 double ReadDouble() {
1266 token_ = ptr_;
1267 double val;
1268 memcpy(&val, Read(sizeof(double)), sizeof(double));
1269 return this->Convert(val);
1270 }
1271
1272 fmt::StringRef ReadString() {
1273 int length = ReadUInt();
1274 return fmt::StringRef(length != 0 ? Read(length) : 0, length);
1275 }
1276
1277 // Reads a function or suffix name.
1278 fmt::StringRef ReadName() { return ReadString(); }
1279 };
1280
1281 // An NLHandler that forwards notification of variable bounds to another
1282 // handler and ignores all other notifications.
1283 template <typename Handler>
1284 class VarBoundHandler : public NullNLHandler<typename Handler::Expr> {
1285 private:
1286 Handler &handler_;
1287
1288 public:
1289 explicit VarBoundHandler(Handler &h) : handler_(h) {}
1290
1291 void OnVarBounds(int index, double lb, double ub) {
1292 handler_.OnVarBounds(index, lb, ub);
1293 }
1294 };
1295
1296 // Linear expression handler that ignores input.
1297 struct NullLinearExprHandler {
1298 void AddTerm(int, double) {}
1299 };
1300
1301 // An NL reader.
1302 // Handler: a class implementing the NLHandler concept that receives
1303 // notifications of NL constructs
1304 template <typename Reader, typename Handler>
1305 class NLReader {
1306 private:
1307 Reader &reader_;
1308 const NLHeader &header_;
1309 Handler &handler_;
1310 int flags_;
1311 int num_vars_and_exprs_; // Number of variables and common expressions.
1312
1313 typedef typename Handler::Expr Expr;
1314 typedef typename Handler::NumericExpr NumericExpr;
1315 typedef typename Handler::LogicalExpr LogicalExpr;
1316 typedef typename Handler::Reference Reference;
1317
1318 double ReadConstant(char code);
1319 double ReadConstant() { return ReadConstant(reader_.ReadChar()); }
1320
1321 // Reads a nonnegative integer and checks that it is less than ub.
1322 // ub is unsigned so that it can hold value INT_MAX + 1u.
1323 int ReadUInt(unsigned ub) {
1324 int value = reader_.ReadUInt();
1325 unsigned unsigned_value = value;
1326 if (unsigned_value >= ub)
1327 reader_.ReportError("integer {} out of bounds", value);
1328 return value;
1329 }
1330
1331 // Reads a nonnegative integer and checks that it is in the range [lb, ub).
1332 int ReadUInt(unsigned lb, unsigned ub) {
1333 int value = reader_.ReadUInt();
1334 unsigned unsigned_value = value;
1335 if (unsigned_value < lb || unsigned_value >= ub)
1336 reader_.ReportError("integer {} out of bounds", value);
1337 return value;
1338 }
1339
1340 // Minimum number of arguments for an iterated expression that has a
1341 // binary counterpart. Examples: sum (+), forall (&&), exists (||).
1342 enum {MIN_ITER_ARGS = 3};
1343
1344 int ReadNumArgs(int min_args = MIN_ITER_ARGS) {
1345 int num_args = reader_.ReadUInt();
1346 if (num_args < min_args)
1347 reader_.ReportError("too few arguments");
1348 return num_args;
1349 }
1350
1351 // Reads a variable or a common expression reference.
1352 Reference DoReadReference() {
1353 int index = ReadUInt(num_vars_and_exprs_);
1354 reader_.ReadTillEndOfLine();
1355 return index < header_.num_vars ?
1356 handler_.OnVariableRef(index) :
1357 handler_.OnCommonExprRef(index - header_.num_vars);
1358 }
1359
1360 // Reads a variable or a common expression reference.
1361 Reference ReadReference() {
1362 if (reader_.ReadChar() != 'v')
1363 reader_.ReportError("expected reference");
1364 return DoReadReference();
1365 }
1366
1367 template <typename ExprReader, typename ArgHandler>
1368 void DoReadArgs(int num_args, ArgHandler &arg_handler) {
1369 ExprReader expr_reader;
1370 for (int i = 0; i < num_args; ++i)
1371 arg_handler.AddArg(expr_reader.Read(*this));
1372 }
1373
1374 template <typename ExprReader, typename ArgHandler>
1375 void ReadArgs(int num_args, ArgHandler &arg_handler) {
1376 reader_.ReadTillEndOfLine();
1377 DoReadArgs<ExprReader>(num_args, arg_handler);
1378 }
1379
1380 int ReadOpCode() {
1381 int opcode = reader_.ReadUInt();
1382 if (opcode > internal::MAX_OPCODE)
1383 reader_.ReportError("invalid opcode {}", opcode);
1384 reader_.ReadTillEndOfLine();
1385 return opcode;
1386 }
1387
1388 typename Handler::CountExpr ReadCountExpr() {
1389 int num_args = ReadNumArgs(1);
1390 typename Handler::CountArgHandler args = handler_.BeginCount(num_args);
1391 ReadArgs<LogicalExprReader>(num_args, args);
1392 return handler_.EndCount(args);
1393 }
1394
1395 // Helper structs to provide a uniform interface to Read{Numeric,Logical}Expr
1396 // since it is not possible to overload on expression type as NumericExpr
1397 // and LogicalExpr can be the same type.
1398 struct NumericExprReader {
1399 typedef NumericExpr Expr;
1400 Expr Read(NLReader &r) const { return r.ReadNumericExpr(); }
1401 };
1402 struct LogicalExprReader {
1403 typedef LogicalExpr Expr;
1404 Expr Read(NLReader &r) const { return r.ReadLogicalExpr(); }
1405 };
1406 struct SymbolicExprReader {
1407 typedef typename Handler::Expr Expr;
1408 Expr Read(NLReader &r) const { return r.ReadSymbolicExpr(); }
1409 };
1410
1411 // A helper struct used to make sure that the arguments to a binary
1412 // expression are read in the correct order and avoid errors of the form:
1413 // MakeBinary(opcode, ReadNumericExpr(), ReadNumericExpr())
1414 // The above code is incorrect as the order of evaluation of arguments is
1415 // unspecified.
1416 template <typename ExprReader = NumericExprReader>
1417 struct BinaryArgReader {
1418 typename ExprReader::Expr lhs;
1419 typename ExprReader::Expr rhs;
1420 BinaryArgReader(NLReader &r)
1421 : lhs(ExprReader().Read(r)), rhs(ExprReader().Read(r)) {}
1422 };
1423
1424 // Reads a numeric or string expression.
1425 Expr ReadSymbolicExpr();
1426
1427 // Reads a numeric expression.
1428 // ignore_zero: if true, zero constants are ignored
1429 NumericExpr ReadNumericExpr(bool ignore_zero = false) {
1430 return ReadNumericExpr(reader_.ReadChar(), ignore_zero);
1431 }
1432 NumericExpr ReadNumericExpr(char code, bool ignore_zero);
1433 NumericExpr ReadNumericExpr(int opcode);
1434
1435 // Reads a logical expression.
1436 LogicalExpr ReadLogicalExpr();
1437 LogicalExpr ReadLogicalExpr(int opcode);
1438
1439 enum ItemType { VAR, OBJ, CON, PROB };
1440
1441 template <ItemType T>
1442 class ItemHandler {
1443 protected:
1444 NLReader &reader_;
1445
1446 public:
1447 static const ItemType TYPE = T;
1448 explicit ItemHandler(NLReader &r) : reader_(r) {}
1449 };
1450
1451 struct VarHandler : ItemHandler<VAR> {
1452 explicit VarHandler(NLReader &r) : ItemHandler<VAR>(r) {}
1453
1454 int num_items() const { return this->reader_.header_.num_vars; }
1455
1456 void SetBounds(int index, double lb, double ub) {
1457 this->reader_.handler_.OnVarBounds(index, lb, ub);
1458 }
1459 void SetInitialValue(int index, double value) {
1460 this->reader_.handler_.OnInitialValue(index, value);
1461 }
1462 };
1463
1464 struct ObjHandler : ItemHandler<OBJ> {
1465 explicit ObjHandler(NLReader &r) : ItemHandler<OBJ>(r) {}
1466
1467 int num_items() const { return this->reader_.header_.num_objs; }
1468
1469 // Returns true if objective expression should be skipped.
1470 bool SkipExpr(int obj_index) const {
1471 return !this->reader_.handler_.NeedObj(obj_index);
1472 }
1473
1474 typename Handler::LinearObjHandler OnLinearExpr(int index, int num_terms) {
1475 auto& h = this->reader_.handler_;
1476 return h.OnLinearObjExpr( h.resulting_obj_index(index), num_terms);
1477 }
1478 };
1479
1480 struct ConHandler : ItemHandler<CON> {
1481 explicit ConHandler(NLReader &r) : ItemHandler<CON>(r) {}
1482
1483 int num_items() const {
1484 return this->reader_.header_.num_algebraic_cons +
1485 this->reader_.header_.num_logical_cons;
1486 }
1487 };
1488
1489 struct ProblemHandler : ItemHandler<PROB> {
1490 explicit ProblemHandler(NLReader &r) : ItemHandler<PROB>(r) {}
1491
1492 // An NL input always contains one problem.
1493 int num_items() const { return 1; }
1494 };
1495
1496 // Reads the linear part of an objective or constraint expression.
1497 template <typename LinearHandler>
1498 void ReadLinearExpr();
1499
1500 template <typename LinearHandler>
1501 void ReadLinearExpr(int num_terms, LinearHandler linear_expr);
1502
1503 // Reads column sizes, numbers of nonzeros in the first num_var ��� 1
1504 // columns of the Jacobian sparsity matrix.
1505 template <bool CUMULATIVE>
1506 void ReadColumnSizes();
1507
1508 // Reads initial values for primal or dual variables.
1509 template <typename ValueHandler>
1510 void ReadInitialValues();
1511
1512 struct IntReader {
1513 int operator()(Reader &r) const { return r.template ReadInt<int>(); }
1514 };
1515
1516 struct DoubleReader {
1517 double operator()(Reader &r) const { return r.ReadDouble(); }
1518 };
1519
1520 template <typename ValueReader, typename SuffixHandler>
1521 void ReadSuffixValues(int num_values, int num_items, SuffixHandler &handler) {
1522 ValueReader read;
1523 for (int i = 0; i < num_values; ++i) {
1524 int index = ReadUInt(num_items);
1525 handler.SetValue(index, read(reader_));
1526 reader_.ReadTillEndOfLine();
1527 }
1528 }
1529
1530 template <typename ItemInfo>
1531 void ReadSuffix(int info);
1532
1533 public:
1534 NLReader(Reader &reader, const NLHeader &header, Handler &handler, int flags)
1535 : reader_(reader), header_(header), handler_(handler), flags_(flags),
1536 num_vars_and_exprs_(0) {}
1537
1538 // Algebraic constraint handler.
1539 struct AlgebraicConHandler : ItemHandler<CON> {
1540 explicit AlgebraicConHandler(NLReader &r) : ItemHandler<CON>(r) {}
1541
1542 int num_items() const { return this->reader_.header_.num_algebraic_cons; }
1543
1544 // Returns false because constraint expressions are always read.
1545 bool SkipExpr(int) const { return false; }
1546
1547 typename Handler::LinearConHandler OnLinearExpr(int index, int num_terms) {
1548 return this->reader_.handler_.OnLinearConExpr(index, num_terms);
1549 }
1550
1551 void SetBounds(int index, double lb, double ub) {
1552 this->reader_.handler_.OnConBounds(index, lb, ub);
1553 }
1554 void SetInitialValue(int index, double value) {
1555 this->reader_.handler_.OnInitialDualValue(index, value);
1556 }
1557 };
1558
1559 // Reads variable or constraint bounds.
1560 template <typename BoundHandler>
1561 void ReadBounds();
1562
1563 // bound_reader: a reader after variable bounds section input
1564 void Read(Reader *bound_reader);
1565
1566 void Read();
1567 };
1568
1569 template <typename Reader, typename Handler>
1570 double NLReader<Reader, Handler>::ReadConstant(char code) {
1571 double value = 0;
1572 switch (code) {
1573 case 'n':
1574 value = reader_.ReadDouble();
1575 break;
1576 case 's':
1577 value = reader_.template ReadInt<short>();
1578 break;
1579 case 'l':
1580 // The following check is necessary for compatibility with ASL.
1581 if (sizeof(double) == 2 * sizeof(int))
1582 value = reader_.template ReadInt<int>();
1583 else
1584 value = reader_.template ReadInt<long>();
1585 break;
1586 default:
1587 reader_.ReportError("expected constant");
1588 }
1589 reader_.ReadTillEndOfLine();
1590 return value;
1591 }
1592
1593 template <typename Reader, typename Handler>
1594 typename Handler::Expr NLReader<Reader, Handler>::ReadSymbolicExpr() {
1595 char c = reader_.ReadChar();
1596 switch (c) {
1597 case 'h':
1598 return handler_.OnString(reader_.ReadString());
1599 case 'o': {
1600 int opcode = ReadOpCode();
1601 if (opcode != expr::nl_opcode(expr::IFSYM))
1602 return ReadNumericExpr(opcode);
1603 // Read symbolic if expression.
1604 LogicalExpr condition = ReadLogicalExpr();
1605 Expr then_expr = ReadSymbolicExpr();
1606 Expr else_expr = ReadSymbolicExpr();
1607 return handler_.OnSymbolicIf(condition, then_expr, else_expr);
1608 }
1609 }
1610 return ReadNumericExpr(c, false);
1611 }
1612
1613 template <typename Reader, typename Handler>
1614 typename Handler::NumericExpr
1615 NLReader<Reader, Handler>::ReadNumericExpr(char code, bool ignore_zero) {
1616 switch (code) {
1617 case 'f': {
1618 // Read a function call.
1619 int func_index = ReadUInt(header_.num_funcs);
1620 int num_args = reader_.ReadUInt();
1621 reader_.ReadTillEndOfLine();
1622 typename Handler::CallArgHandler args =
1623 handler_.BeginCall(func_index, num_args);
1624 for (int i = 0; i < num_args; ++i)
1625 args.AddArg(ReadSymbolicExpr());
1626 return handler_.EndCall(args);
1627 }
1628 case 'n': case 'l': case 's': {
1629 // Read a number.
1630 double value = ReadConstant(code);
1631 if (ignore_zero && value == 0)
1632 break; // Ignore zero constant.
1633 return handler_.OnNumber(value);
1634 }
1635 case 'o':
1636 return ReadNumericExpr(ReadOpCode());
1637 case 'v':
1638 return DoReadReference();
1639 default:
1640 reader_.ReportError("expected expression");
1641 }
1642 return NumericExpr();
1643 }
1644
1645 template <typename Reader, typename Handler>
1646 typename Handler::NumericExpr
1647 NLReader<Reader, Handler>::ReadNumericExpr(int opcode) {
1648 const internal::OpCodeInfo &info = internal::GetOpCodeInfo(opcode);
1649 expr::Kind kind = info.kind;
1650 switch (info.first_kind) {
1651 case expr::FIRST_UNARY:
1652 return handler_.OnUnary(kind, ReadNumericExpr());
1653 case expr::FIRST_BINARY: {
1654 BinaryArgReader<> args(*this);
1655 return handler_.OnBinary(kind, args.lhs, args.rhs);
1656 }
1657 case expr::IF: {
1658 LogicalExpr condition = ReadLogicalExpr();
1659 NumericExpr then_expr = ReadNumericExpr();
1660 NumericExpr else_expr = ReadNumericExpr();
1661 return handler_.OnIf(condition, then_expr, else_expr);
1662 }
1663 case expr::PLTERM: {
1664 // Read a piecewise-linear term.
1665 int num_slopes = reader_.ReadUInt();
1666 if (num_slopes <= 1)
1667 reader_.ReportError("too few slopes in piecewise-linear term");
1668 reader_.ReadTillEndOfLine();
1669 typename Handler::PLTermHandler pl_handler =
1670 handler_.BeginPLTerm(num_slopes - 1);
1671 for (int i = 0; i < num_slopes - 1; ++i) {
1672 pl_handler.AddSlope(ReadConstant());
1673 pl_handler.AddBreakpoint(ReadConstant());
1674 }
1675 pl_handler.AddSlope(ReadConstant());
1676 return handler_.EndPLTerm(pl_handler, ReadReference());
1677 }
1678 case expr::FIRST_VARARG: {
1679 // Read a vararg expression (min or max).
1680 int num_args = ReadNumArgs(1);
1681 typename Handler::VarArgHandler args = handler_.BeginVarArg(kind, num_args);
1682 ReadArgs<NumericExprReader>(num_args, args);
1683 return handler_.EndVarArg(args);
1684 }
1685 case expr::SUM: {
1686 int num_args = ReadNumArgs();
1687 typename Handler::NumericArgHandler args = handler_.BeginSum(num_args);
1688 ReadArgs<NumericExprReader>(num_args, args);
1689 return handler_.EndSum(args);
1690 }
1691 case expr::COUNT:
1692 return ReadCountExpr();
1693 case expr::NUMBEROF: {
1694 // Read a numberof expression.
1695 int num_args = ReadNumArgs(1);
1696 reader_.ReadTillEndOfLine();
1697 typename Handler::NumberOfArgHandler args =
1698 handler_.BeginNumberOf(num_args, ReadNumericExpr());
1699 DoReadArgs<NumericExprReader>(num_args - 1, args);
1700 return handler_.EndNumberOf(args);
1701 }
1702 case expr::NUMBEROF_SYM: {
1703 // Read a symbolic numberof expression.
1704 int num_args = ReadNumArgs(1);
1705 reader_.ReadTillEndOfLine();
1706 typename Handler::SymbolicArgHandler args =
1707 handler_.BeginSymbolicNumberOf(num_args, ReadSymbolicExpr());
1708 DoReadArgs<SymbolicExprReader>(num_args - 1, args);
1709 return handler_.EndSymbolicNumberOf(args);
1710 }
1711 default:
1712 reader_.ReportError("expected numeric expression opcode");
1713 }
1714 return NumericExpr();
1715 }
1716
1717 template <typename Reader, typename Handler>
1718 typename Handler::LogicalExpr NLReader<Reader, Handler>::ReadLogicalExpr() {
1719 switch (char c = reader_.ReadChar()) {
1720 case 'n': case 'l': case 's':
1721 return handler_.OnBool(ReadConstant(c) != 0);
1722 case 'o':
1723 return ReadLogicalExpr(ReadOpCode());
1724 }
1725 reader_.ReportError("expected logical expression");
1726 return LogicalExpr();
1727 }
1728
1729 template <typename Reader, typename Handler>
1730 typename Handler::LogicalExpr
1731 NLReader<Reader, Handler>::ReadLogicalExpr(int opcode) {
1732 const internal::OpCodeInfo &info = internal::GetOpCodeInfo(opcode);
1733 expr::Kind kind = info.kind;
1734 switch (info.first_kind) {
1735 case expr::NOT:
1736 return handler_.OnNot(ReadLogicalExpr());
1737 case expr::FIRST_BINARY_LOGICAL: {
1738 BinaryArgReader<LogicalExprReader> args(*this);
1739 return handler_.OnBinaryLogical(kind, args.lhs, args.rhs);
1740 }
1741 case expr::FIRST_RELATIONAL: {
1742 BinaryArgReader<> args(*this);
1743 return handler_.OnRelational(kind, args.lhs, args.rhs);
1744 }
1745 case expr::FIRST_LOGICAL_COUNT: {
1746 NumericExpr lhs = ReadNumericExpr();
1747 char c = reader_.ReadChar();
1748 if (c != 'o' || internal::GetOpCodeInfo(ReadOpCode()).kind != expr::COUNT)
1749 reader_.ReportError("expected count expression");
1750 return handler_.OnLogicalCount(kind, lhs, ReadCountExpr());
1751 }
1752 case expr::IMPLICATION: {
1753 // Read an implication (=>).
1754 LogicalExpr condition = ReadLogicalExpr();
1755 LogicalExpr then_expr = ReadLogicalExpr();
1756 LogicalExpr else_expr = ReadLogicalExpr();
1757 return handler_.OnImplication(condition, then_expr, else_expr);
1758 }
1759 case expr::FIRST_ITERATED_LOGICAL: {
1760 // Read an iterated logical expression (exists or forall).
1761 int num_args = ReadNumArgs();
1762 typename Handler::LogicalArgHandler args =
1763 handler_.BeginIteratedLogical(kind, num_args);
1764 ReadArgs<LogicalExprReader>(num_args, args);
1765 return handler_.EndIteratedLogical(args);
1766 }
1767 case expr::FIRST_PAIRWISE: {
1768 // Read a pairwise expression (alldiff or !alldiff).
1769 int num_args = ReadNumArgs(1);
1770 typename Handler::PairwiseArgHandler args =
1771 handler_.BeginPairwise(kind, num_args);
1772 ReadArgs<NumericExprReader>(num_args, args);
1773 return handler_.EndPairwise(args);
1774 }
1775 default:
1776 reader_.ReportError("expected logical expression opcode");
1777 }
1778 return LogicalExpr();
1779 }
1780
1781 template <typename Reader, typename Handler>
1782 template <typename LinearHandler>
1783 void NLReader<Reader, Handler>::ReadLinearExpr() {
1784 LinearHandler lh(*this);
1785 int index = ReadUInt(lh.num_items());
1786 // The number of terms should be less than num_vars because common
1787 // expressions are not allowed in a linear expression.
1788 int num_terms = ReadUInt(1, header_.num_vars + 1u);
1789 reader_.ReadTillEndOfLine();
1790 if (lh.SkipExpr(index))
1791 ReadLinearExpr(num_terms, NullLinearExprHandler());
1792 else
1793 ReadLinearExpr(num_terms, lh.OnLinearExpr(index, num_terms));
1794 }
1795
1796 template <typename Reader, typename Handler>
1797 template <typename LinearHandler>
1798 void NLReader<Reader, Handler>::ReadLinearExpr(
1799 int num_terms, LinearHandler linear_expr) {
1800 for (int i = 0; i < num_terms; ++i) {
1801 // Variable index should be less than num_vars because common
1802 // expressions are not allowed in a linear expression.
1803 int var_index = ReadUInt(header_.num_vars);
1804 double coef = reader_.ReadDouble();
1805 reader_.ReadTillEndOfLine();
1806 linear_expr.AddTerm(var_index, coef);
1807 }
1808 }
1809
1810 template <typename Reader, typename Handler>
1811 template <typename BoundHandler>
1812 void NLReader<Reader, Handler>::ReadBounds() {
1813 enum BoundType {
1814 RANGE, // Both lower and upper bounds: l <= body <= u.
1815 UPPER, // Only upper bound: body <= u.
1816 LOWER, // Only lower bound: l <= body.
1817 FREE, // No constraints on body (free variable or constraint).
1818 CONSTANT, // Equal to constant: body = c.
1819 COMPL // Body complements variable v[i - 1].
1820 };
1821 reader_.ReadTillEndOfLine();
1822 double lb = 0, ub = 0;
1823 BoundHandler bh(*this);
1824 int num_bounds = bh.num_items();
1825 double infinity = std::numeric_limits<double>::infinity();
1826 for (int i = 0; i < num_bounds; ++i) {
1827 switch (reader_.ReadChar() - '0') {
1828 case RANGE:
1829 lb = reader_.ReadDouble();
1830 ub = reader_.ReadDouble();
1831 break;
1832 case UPPER:
1833 lb = -infinity;
1834 ub = reader_.ReadDouble();
1835 break;
1836 case LOWER:
1837 lb = reader_.ReadDouble();
1838 ub = infinity;
1839 break;
1840 case FREE:
1841 lb = -infinity;
1842 ub = infinity;
1843 break;
1844 case CONSTANT:
1845 lb = ub = reader_.ReadDouble();
1846 break;
1847 case COMPL:
1848 if (BoundHandler::TYPE == CON) {
1849 int flags = reader_.template ReadInt<int>();
1850 int var_index = reader_.ReadUInt();
1851 // Don't use NLReader::ReadUInt(int, int) as num_vars + 1 may overflow.
1852 if (var_index == 0 || var_index > header_.num_vars)
1853 reader_.ReportError("integer {} out of bounds", var_index);
1854 --var_index;
1855 int mask = ComplInfo::INF_LB | ComplInfo::INF_UB;
1856 handler_.OnComplementarity(i, var_index, ComplInfo(flags & mask));
1857 reader_.ReadTillEndOfLine();
1858 continue;
1859 }
1860 reader_.ReportError("COMPL bound type is invalid for variables");
1861 break;
1862 default:
1863 reader_.ReportError("expected bound");
1864 }
1865 reader_.ReadTillEndOfLine();
1866 bh.SetBounds(i, lb, ub);
1867 }
1868 }
1869
1870 template <typename Reader, typename Handler>
1871 template <bool CUMULATIVE>
1872 void NLReader<Reader, Handler>::ReadColumnSizes() {
1873 int num_sizes = header_.num_vars - 1;
1874 if (reader_.ReadUInt() != num_sizes)
1875 reader_.ReportError("expected {}", num_sizes);
1876 reader_.ReadTillEndOfLine();
1877 typename Handler::ColumnSizeHandler size_handler = handler_.OnColumnSizes();
1878 int prev_size = 0;
1879 for (int i = 0; i < num_sizes; ++i) {
1880 int size = reader_.ReadUInt();
1881 if (CUMULATIVE) {
1882 if (size < prev_size)
1883 reader_.ReportError("invalid column offset");
1884 size -= prev_size;
1885 prev_size += size;
1886 }
1887 size_handler.Add(size);
1888 reader_.ReadTillEndOfLine();
1889 }
1890 }
1891
1892 template <typename Reader, typename Handler>
1893 template <typename ValueHandler>
1894 void NLReader<Reader, Handler>::ReadInitialValues() {
1895 int num_values = reader_.ReadUInt();
1896 ValueHandler vh(*this);
1897 if (num_values > vh.num_items())
1898 reader_.ReportError("too many initial values");
1899 reader_.ReadTillEndOfLine();
1900 for (int i = 0; i < num_values; ++i) {
1901 int index = ReadUInt(vh.num_items());
1902 vh.SetInitialValue(index, reader_.ReadDouble());
1903 reader_.ReadTillEndOfLine();
1904 }
1905 }
1906
1907 template <typename Reader, typename Handler>
1908 template <typename ItemInfo>
1909 void NLReader<Reader, Handler>::ReadSuffix(int info) {
1910 int num_items = ItemInfo(*this).num_items();
1911 int num_values = ReadUInt(1, num_items + 1);
1912 fmt::StringRef name = reader_.ReadName();
1913 reader_.ReadTillEndOfLine();
1914 suf::Kind kind = static_cast<suf::Kind>(info & internal::SUFFIX_KIND_MASK);
1915 if ((info & suf::FLOAT) != 0) {
1916 typename Handler::DblSuffixHandler
1917 suffix_handler = handler_.OnDblSuffix(name, kind, num_values);
1918 ReadSuffixValues<DoubleReader>(num_values, num_items, suffix_handler);
1919 } else {
1920 typename Handler::IntSuffixHandler
1921 suffix_handler = handler_.OnIntSuffix(name, kind, num_values);
1922 ReadSuffixValues<IntReader>(num_values, num_items, suffix_handler);
1923 }
1924 }
1925
1926 template <typename Reader, typename Handler>
1927 void NLReader<Reader, Handler>::Read(Reader *bound_reader) {
1928 bool read_bounds = bound_reader == 0;
1929 // TextReader::ReadHeader checks that this doesn't overflow.
1930 num_vars_and_exprs_ = header_.num_vars +
1931 header_.num_common_exprs_in_both +
1932 header_.num_common_exprs_in_cons +
1933 header_.num_common_exprs_in_objs +
1934 header_.num_common_exprs_in_single_cons +
1935 header_.num_common_exprs_in_single_objs;
1936 for (;;) {
1937 char c = reader_.ReadChar();
1938 switch (c) {
1939 case 'C': {
1940 // Nonlinear part of an algebraic constraint body.
1941 int index = ReadUInt(header_.num_algebraic_cons);
1942 reader_.ReadTillEndOfLine();
1943 handler_.OnAlgebraicCon(index, ReadNumericExpr(true));
1944 break;
1945 }
1946 case 'L': {
1947 // Logical constraint expression.
1948 int index = ReadUInt(header_.num_logical_cons);
1949 reader_.ReadTillEndOfLine();
1950 handler_.OnLogicalCon(index, ReadLogicalExpr());
1951 break;
1952 }
1953 case 'O': {
1954 // Objective type and nonlinear part of an objective expression.
1955 int index = ReadUInt(header_.num_objs);
1956 int obj_type = reader_.ReadUInt();
1957 reader_.ReadTillEndOfLine();
1958 NumericExpr expr = ReadNumericExpr(true);
1959 if (handler_.NeedObj(index))
1960 handler_.OnObj(handler_.resulting_obj_index(index),
1961 obj_type != 0 ? obj::MAX : obj::MIN,
1962 expr);
1963 break;
1964 }
1965 case 'V': {
1966 // Defined variable definition (must precede V, C, L, O segments
1967 // where used).
1968 int expr_index = ReadUInt(header_.num_vars, num_vars_and_exprs_);
1969 expr_index -= header_.num_vars;
1970 int num_linear_terms = reader_.ReadUInt();
1971 int position = reader_.ReadUInt();
1972 reader_.ReadTillEndOfLine();
1973 typename Handler::LinearExprHandler
1974 expr_handler(handler_.BeginCommonExpr(expr_index, num_linear_terms));
1975 if (num_linear_terms != 0)
1976 ReadLinearExpr(num_linear_terms, expr_handler);
1977 handler_.EndCommonExpr(expr_index, ReadNumericExpr(), position);
1978 break;
1979 }
1980 case 'F': {
1981 // Imported function description.
1982 int index = ReadUInt(header_.num_funcs);
1983 int type = reader_.ReadUInt();
1984 if (type != func::NUMERIC && type != func::SYMBOLIC)
1985 reader_.ReportError("invalid function type");
1986 int num_args = reader_.template ReadInt<int>();
1987 fmt::StringRef name = reader_.ReadName();
1988 reader_.ReadTillEndOfLine();
1989 handler_.OnFunction(index, name, num_args, static_cast<func::Type>(type));
1990 break;
1991 }
1992 case 'G':
1993 // Linear part of an objective expression & gradient sparsity.
1994 ReadLinearExpr<ObjHandler>();
1995 break;
1996 case 'J':
1997 // Jacobian sparsity & linear terms in constraints.
1998 ReadLinearExpr<AlgebraicConHandler>();
1999 break;
2000 case 'S': {
2001 // Suffix values.
2002 int info = reader_.ReadUInt();
2003 if (info > (internal::SUFFIX_KIND_MASK | suf::FLOAT))
2004 reader_.ReportError("invalid suffix kind");
2005 switch (info & internal::SUFFIX_KIND_MASK) {
2006 case suf::VAR:
2007 ReadSuffix<VarHandler>(info);
2008 break;
2009 case suf::CON:
2010 ReadSuffix<ConHandler>(info);
2011 break;
2012 case suf::OBJ:
2013 ReadSuffix<ObjHandler>(info);
2014 break;
2015 case suf::PROBLEM:
2016 ReadSuffix<ProblemHandler>(info);
2017 break;
2018 }
2019 break;
2020 }
2021 case 'b':
2022 // Bounds on variables.
2023 if (read_bounds) {
2024 ReadBounds<VarHandler>();
(1) Event side_effect_free: |
Calling "this->reader_->ptr()" is only useful for its return value, which is ignored. [details] |
2025 reader_.ptr();
2026 if ((flags_ & READ_BOUNDS_FIRST) != 0)
2027 return;
2028 read_bounds = false;
2029 break;
2030 }
2031 if (!bound_reader)
2032 reader_.ReportError("duplicate 'b' segment");
2033 reader_ = *bound_reader;
2034 bound_reader = 0;
2035 break;
2036 case 'r':
2037 // Bounds on algebraic constraint bodies ("ranges").
2038 ReadBounds<AlgebraicConHandler>();
2039 break;
2040 case 'K':
2041 // Jacobian sparsity & linear constraint term matrix column sizes
2042 // (must precede all J segments).
2043 ReadColumnSizes<false>();
2044 break;
2045 case 'k':
2046 // Jacobian sparsity & linear constraint term matrix cumulative column
2047 // sizes (must precede all J segments).
2048 ReadColumnSizes<true>();
2049 break;
2050 case 'x':
2051 // Primal initial guess.
2052 ReadInitialValues<VarHandler>();
2053 break;
2054 case 'd':
2055 // Dual initial guess.
2056 ReadInitialValues<AlgebraicConHandler>();
2057 break;
2058 case '\0':
2059 if (reader_.IsEOF()) {
2060 if (read_bounds)
2061 reader_.ReportError("segment 'b' missing");
2062 return;
2063 }
2064 // Fall through.
2065 default:
2066 reader_.ReportError("invalid segment type");
2067 }
2068 }
2069 }
2070
2071 template <typename Reader, typename Handler>
2072 void NLReader<Reader, Handler>::Read() {
2073 if ((flags_ & READ_BOUNDS_FIRST) != 0) {
2074 // Read variable bounds first because this allows more efficient
2075 // problem construction.
2076 VarBoundHandler<Handler> bound_handler(handler_);
2077 Reader bound_reader(reader_);
2078 NLReader< Reader, VarBoundHandler<Handler> >
2079 reader(bound_reader, header_, bound_handler, flags_);
2080 reader.Read(0);
2081 // Read everything else.
2082 Read(&bound_reader);
2083 } else {
2084 Read(0);
2085 }
2086 handler_.EndInput();
2087 }
2088
2089 // An .nl file reader.
2090 template <typename File = fmt::File>
2091 class NLFileReader {
2092 private:
2093 File file_;
2094 std::size_t size_;
2095 std::size_t rounded_size_; // Size rounded up to a multiple of page size.
2096
2097 void Open(fmt::CStringRef filename);
2098
2099 // Reads the file into an array.
2100 void Read(fmt::internal::MemoryBuffer<char, 1> &array);
2101
2102 public:
2103 NLFileReader() : size_(0), rounded_size_(0) {}
2104
2105 const File &file() { return file_; }
2106
2107 // Opens and reads the file.
2108 template <typename Handler>
2109 void Read(fmt::CStringRef filename, Handler &handler, int flags) {
2110 Open(filename);
2111 if (size_ == rounded_size_) {
2112 // Don't use mmap, because the file size is a multiple of the page size
2113 // and therefore the mmap'ed buffer won't be null-terminated.
2114 fmt::internal::MemoryBuffer<char, 1> array;
2115 Read(array);
2116 return ReadNLString(
2117 NLStringRef(&array[0], size_), handler, filename, flags);
2118 }
2119 MemoryMappedFile<File> mapped_file(file_, rounded_size_);
2120 ReadNLString(
2121 NLStringRef(mapped_file.start(), size_), handler, filename, flags);
2122 }
2123 };
2124
2125 template <typename InputConverter, typename Handler>
2126 void ReadBinary(TextReader<> &reader, const NLHeader &header,
2127 Handler &handler, int flags) {
2128 BinaryReader<InputConverter> bin_reader(reader);
2129 NLReader<BinaryReader<InputConverter>, Handler>(
2130 bin_reader, header, handler, flags).Read();
2131 }
2132
2133 template <typename NameHandler>
2134 void ReadNames(fmt::CStringRef filename, fmt::StringRef data,
2135 NameHandler &handler) {
2136 int line = 1;
2137 const char *start = data.data();
2138 const char *end = start + data.size();
2139 for (const char *ptr = start; ptr != end; ++ptr) {
2140 if (*ptr == '\n') {
2141 handler.OnName(fmt::StringRef(start, ptr - start));
2142 start = ptr + 1;
2143 ++line;
2144 }
2145 }
2146 if (start != end) {
2147 int column = static_cast<int>(end - start + 1);
2148 throw ReadError(filename, line, column, "missing newline");
2149 }
2150 }
2151
2152 // A name file reader.
2153 class NameReader {
2154 private:
2155 MemoryMappedFile<> mapped_file_;
2156
2157 public:
2158 // Reads names from the file *filename* sending the names to the *handler*
2159 // object by calling ``handler.OnName(name)``. The name argument to
2160 // ``OnName`` is a ``fmt::StringRef`` object and the string it refers to
2161 // is not null-terminated.
2162 // Each name in the input file should be on a separate line ended with a
2163 // newline character ('\n').
2164 template <typename NameHandler>
2165 void Read(fmt::CStringRef filename, NameHandler &handler) {
2166 fmt::File file(filename, fmt::File::RDONLY);
2167 mapped_file_.map(file, filename);
2168 fmt::StringRef data(mapped_file_.start(), mapped_file_.size());
2169 ReadNames(filename, data, handler);
2170 }
2171 };
2172
2173 // An NL handler that constructs an optimization problem using ProblemBuilder.
2174 template <typename ProblemBuilder>
2175 class NLProblemBuilder {
2176 public:
2177 typedef typename ProblemBuilder::Function Function;
2178 typedef typename ProblemBuilder::Expr Expr;
2179 typedef typename ProblemBuilder::NumericExpr NumericExpr;
2180 typedef typename ProblemBuilder::LogicalExpr LogicalExpr;
2181 typedef typename ProblemBuilder::CountExpr CountExpr;
2182 typedef typename ProblemBuilder::Reference Reference;
2183
2184 private:
2185 ProblemBuilder &builder_;
2186
2187 template <typename Obj>
2188 void SetObj(const Obj &obj, obj::Type type, NumericExpr expr) {
2189 obj.set_type(type);
2190 obj.set_nonlinear_expr(expr);
2191 }
2192
2193 // Sets bounds on a problem item (objective or constraint).
2194 template <typename Item>
2195 void SetBounds(const Item &item, double lb, double ub) {
2196 item.set_lb(lb);
2197 item.set_ub(ub);
2198 }
2199
2200 template <typename CommonExpr>
2201 void SetCommonExpr(const CommonExpr &common_expr,
2202 NumericExpr expr, int position) {
2203 common_expr.set_nonlinear_expr(expr);
2204 common_expr.set_position(position);
2205 }
2206
2207 public:
2208 explicit NLProblemBuilder(ProblemBuilder &builder): builder_(builder) {}
2209
2210 ProblemBuilder &builder() { return builder_; }
2211
2212 void OnHeader(const NLHeader &h) {
2213 builder_.SetInfo(h);
2214
2215 // As nl-benchmark shows, adding problem components at once and then
2216 // updating them is faster than adding them incrementally. The latter
2217 // requires additional checks to make sure that prolbem components are
2218 // in the correct order.
2219 if (int n = h.num_continuous_vars())
2220 builder_.AddVars(n, var::CONTINUOUS);
2221 if (int n = h.num_integer_vars())
2222 builder_.AddVars(n, var::INTEGER);
2223 if (int n = h.num_common_exprs())
2224 builder_.AddCommonExprs(n);
2225 int n_objs = resulting_nobj( h.num_objs );
2226 if (n_objs != 0)
2227 builder_.AddObjs( n_objs );
2228 if (h.num_algebraic_cons != 0)
2229 builder_.AddAlgebraicCons(h.num_algebraic_cons);
2230 if (h.num_logical_cons != 0)
2231 builder_.AddLogicalCons(h.num_logical_cons);
2232 if (h.num_funcs != 0)
2233 builder_.AddFunctions(h.num_funcs);
2234 }
2235
2236 virtual int objno() const { return 1; }
2237 virtual bool multiobj() const { return true; }
2238
2239 int resulting_nobj(int nobj_header) const {
2240 return multiobj() ? nobj_header :
2241 std::min( (objno()>0), (nobj_header>0) );
2242 }
2243 bool NeedObj(int obj_index) const {
2244 return multiobj() || objno()-1==obj_index;
2245 }
2246 int resulting_obj_index(int index) const {
2247 if (multiobj())
2248 return index;
2249 assert(objno()-1==index);
2250 return 0;
2251 }
2252
2253 void OnObj(int index, obj::Type type, NumericExpr expr) {
2254 SetObj(builder_.obj(index), type, expr);
2255 }
2256
2257 void OnAlgebraicCon(int index, NumericExpr expr) {
2258 builder_.algebraic_con(index).set_nonlinear_expr(expr);
2259 }
2260
2261 void OnLogicalCon(int index, LogicalExpr expr) {
2262 builder_.logical_con(index).set_expr(expr);
2263 }
2264
2265 void OnComplementarity(int con_index, int var_index, ComplInfo info) {
2266 builder_.SetComplementarity(con_index, var_index, info);
2267 }
2268
2269 typedef typename ProblemBuilder::LinearObjBuilder LinearObjHandler;
2270
2271 LinearObjHandler OnLinearObjExpr(int obj_index, int num_linear_terms) {
2272 return builder_.obj(obj_index).set_linear_expr(num_linear_terms);
2273 }
2274
2275 typedef typename ProblemBuilder::LinearConBuilder LinearConHandler;
2276
2277 LinearConHandler OnLinearConExpr(int con_index, int num_linear_terms) {
2278 return builder_.algebraic_con(con_index).set_linear_expr(num_linear_terms);
2279 }
2280
2281 typedef typename ProblemBuilder::LinearExprBuilder LinearExprHandler;
2282
2283 LinearExprHandler BeginCommonExpr(int index, int num_linear_terms) {
2284 return builder_.common_expr(index).set_linear_expr(num_linear_terms);
2285 }
2286 void EndCommonExpr(int index, NumericExpr expr, int position) {
2287 SetCommonExpr(builder_.common_expr(index), expr, position);
2288 }
2289
2290 void OnVarBounds(int index, double lb, double ub) {
2291 SetBounds(builder_.var(index), lb, ub);
2292 }
2293
2294 void OnConBounds(int index, double lb, double ub) {
2295 SetBounds(builder_.algebraic_con(index), lb, ub);
2296 }
2297
2298 void OnInitialValue(int var_index, double value) {
2299 builder_.var(var_index).set_value(value);
2300 }
2301
2302 void OnInitialDualValue(int con_index, double value) {
2303 builder_.algebraic_con(con_index).set_dual(value);
2304 }
2305
2306 struct ColumnSizeHandler {
2307 void Add(int) {
2308 // Ignore column sizes as the constraints are stored row-wise by default.
2309 }
2310 };
2311
2312 ColumnSizeHandler OnColumnSizes() {
2313 return ColumnSizeHandler();
2314 }
2315
2316 void OnFunction(int index, fmt::StringRef name,
2317 int num_args, func::Type type) {
2318 builder_.DefineFunction(index, name, num_args, type);
2319 }
2320
2321 typedef typename ProblemBuilder::IntSuffixHandler IntSuffixHandler;
2322
2323 IntSuffixHandler OnIntSuffix(fmt::StringRef name, suf::Kind kind,
2324 int num_values) {
2325 return builder_.AddIntSuffix(name, kind, num_values);
2326 }
2327
2328 typedef typename ProblemBuilder::DblSuffixHandler DblSuffixHandler;
2329
2330 DblSuffixHandler OnDblSuffix(fmt::StringRef name, suf::Kind kind,
2331 int num_values) {
2332 return builder_.AddDblSuffix(name, kind, num_values);
2333 }
2334
2335 NumericExpr OnNumber(double value) {
2336 return builder_.MakeNumericConstant(value);
2337 }
2338
2339 Reference OnVariableRef(int var_index) {
2340 return builder_.MakeVariable(var_index);
2341 }
2342
2343 Reference OnCommonExprRef(int expr_index) {
2344 return builder_.MakeCommonExpr(expr_index);
2345 }
2346
2347 NumericExpr OnUnary(expr::Kind kind, NumericExpr arg) {
2348 return builder_.MakeUnary(kind, arg);
2349 }
2350
2351 NumericExpr OnBinary(expr::Kind kind, NumericExpr lhs, NumericExpr rhs) {
2352 return builder_.MakeBinary(kind, lhs, rhs);
2353 }
2354
2355 NumericExpr OnIf(LogicalExpr condition,
2356 NumericExpr then_expr, NumericExpr else_expr) {
2357 return builder_.MakeIf(condition, then_expr, else_expr);
2358 }
2359
2360 typedef typename ProblemBuilder::PLTermBuilder PLTermHandler;
2361
2362 PLTermHandler BeginPLTerm(int num_breakpoints) {
2363 return builder_.BeginPLTerm(num_breakpoints);
2364 }
2365 NumericExpr EndPLTerm(PLTermHandler handler, Reference arg) {
2366 return builder_.EndPLTerm(handler, arg);
2367 }
2368
2369 typedef typename ProblemBuilder::CallExprBuilder CallArgHandler;
2370
2371 CallArgHandler BeginCall(int func_index, int num_args) {
2372 // Check if the function is defined.
2373 if (Function func = builder_.function(func_index))
2374 return builder_.BeginCall(func, num_args);
2375 throw Error("function {} is not defined", func_index);
2376 }
2377 NumericExpr EndCall(CallArgHandler handler) {
2378 return builder_.EndCall(handler);
2379 }
2380
2381 typedef typename ProblemBuilder::IteratedExprBuilder VarArgHandler;
2382
2383 VarArgHandler BeginVarArg(expr::Kind kind, int num_args) {
2384 return builder_.BeginIterated(kind, num_args);
2385 }
2386 NumericExpr EndVarArg(VarArgHandler handler) {
2387 return builder_.EndIterated(handler);
2388 }
2389
2390 typedef typename ProblemBuilder::IteratedExprBuilder NumericArgHandler;
2391
2392 NumericArgHandler BeginSum(int num_args) {
2393 return builder_.BeginSum(num_args);
2394 }
2395 NumericExpr EndSum(NumericArgHandler handler) {
2396 return builder_.EndSum(handler);
2397 }
2398
2399 typedef typename ProblemBuilder::NumberOfExprBuilder NumberOfArgHandler;
2400
2401 NumberOfArgHandler BeginNumberOf(int num_args, NumericExpr arg0) {
2402 return builder_.BeginNumberOf(num_args, arg0);
2403 }
2404 NumericExpr EndNumberOf(NumberOfArgHandler handler) {
2405 return builder_.EndNumberOf(handler);
2406 }
2407
2408 typedef typename ProblemBuilder::SymbolicNumberOfExprBuilder
2409 SymbolicArgHandler;
2410
2411 SymbolicArgHandler BeginSymbolicNumberOf(int num_args, Expr arg0) {
2412 return builder_.BeginSymbolicNumberOf(num_args, arg0);
2413 }
2414 NumericExpr EndSymbolicNumberOf(SymbolicArgHandler handler) {
2415 return builder_.EndSymbolicNumberOf(handler);
2416 }
2417
2418 typedef typename ProblemBuilder::CountExprBuilder CountArgHandler;
2419
2420 CountArgHandler BeginCount(int num_args) {
2421 return builder_.BeginCount(num_args);
2422 }
2423 CountExpr EndCount(CountArgHandler handler) {
2424 return builder_.EndCount(handler);
2425 }
2426
2427 LogicalExpr OnBool(bool value) {
2428 return builder_.MakeLogicalConstant(value);
2429 }
2430
2431 LogicalExpr OnNot(LogicalExpr arg) {
2432 return builder_.MakeNot(arg);
2433 }
2434
2435 LogicalExpr OnBinaryLogical(
2436 expr::Kind kind, LogicalExpr lhs, LogicalExpr rhs) {
2437 return builder_.MakeBinaryLogical(kind, lhs, rhs);
2438 }
2439
2440 LogicalExpr OnRelational(
2441 expr::Kind kind, NumericExpr lhs, NumericExpr rhs) {
2442 return builder_.MakeRelational(kind, lhs, rhs);
2443 }
2444
2445 LogicalExpr OnLogicalCount(
2446 expr::Kind kind, NumericExpr lhs, CountExpr rhs) {
2447 return builder_.MakeLogicalCount(kind, lhs, rhs);
2448 }
2449
2450 LogicalExpr OnImplication(
2451 LogicalExpr condition, LogicalExpr then_expr, LogicalExpr else_expr) {
2452 return builder_.MakeImplication(condition, then_expr, else_expr);
2453 }
2454
2455 typedef typename ProblemBuilder::IteratedLogicalExprBuilder LogicalArgHandler;
2456
2457 LogicalArgHandler BeginIteratedLogical(expr::Kind kind, int num_args) {
2458 return builder_.BeginIteratedLogical(kind, num_args);
2459 }
2460 LogicalExpr EndIteratedLogical(LogicalArgHandler handler) {
2461 return builder_.EndIteratedLogical(handler);
2462 }
2463
2464 typedef typename ProblemBuilder::PairwiseExprBuilder PairwiseArgHandler;
2465
2466 PairwiseArgHandler BeginPairwise(expr::Kind kind, int num_args) {
2467 return builder_.BeginPairwise(kind, num_args);
2468 }
2469 LogicalExpr EndPairwise(PairwiseArgHandler handler) {
2470 return builder_.EndPairwise(handler);
2471 }
2472
2473 Expr OnString(fmt::StringRef value) {
2474 return builder_.MakeStringLiteral(value);
2475 }
2476
2477 Expr OnSymbolicIf(LogicalExpr condition, Expr then_expr, Expr else_expr) {
2478 return builder_.MakeSymbolicIf(condition, then_expr, else_expr);
2479 }
2480
2481 void EndInput() {}
2482 };
2483
2484 template <typename Handler, bool>
2485 struct NLAdapter {
2486 typedef Handler Type;
2487 typedef Handler &RefType;
2488 };
2489
2490 template <typename Handler>
2491 struct NLAdapter<Handler, true> {
2492 typedef NLProblemBuilder<typename Handler::Builder> Type;
2493 typedef Type RefType;
2494 };
2495
2496 // SV added to suppress warning in following class
2497 // see also https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71484#c5
2498 #ifdef __GNUC__
2499 #pragma GCC diagnostic ignored "-Wctor-dtor-privacy"
2500 #endif
2501
2502 // Checks if T has a member type Builder.
2503 template <typename T>
2504 class HasBuilder {
2505 private:
2506 template <typename U> static fmt::internal::Yes &test(typename U::Builder *);
2507 template <typename U> static fmt::internal::No &test(...);
2508 public:
2509 enum {value = sizeof(test<T>(0)) == sizeof(fmt::internal::Yes)};
2510 };
2511 } // namespace internal
2512
2513 template <typename Handler>
2514 void ReadNLString(NLStringRef str, Handler &handler,
2515 fmt::CStringRef name, int flags) {
2516 // If handler is a Problem-like object (Problem::Builder type is defined)
2517 // then use ProblemBuilder API to populate it.
2518 typedef internal::NLAdapter<
2519 Handler, internal::HasBuilder<Handler>::value> Adapter;
2520 typename Adapter::RefType adapter(handler);
2521 internal::TextReader<> reader(str, name);
2522 NLHeader header = NLHeader();
2523 reader.ReadHeader(header);
2524 adapter.OnHeader(header);
2525 switch (header.format) {
2526 case NLHeader::TEXT:
2527 internal::NLReader<internal::TextReader<>, typename Adapter::Type>(
2528 reader, header, adapter, flags).Read();
2529 break;
2530 case NLHeader::BINARY: {
2531 using internal::ReadBinary;
2532 arith::Kind arith_kind = arith::GetKind();
2533 if (arith_kind == header.arith_kind) {
2534 ReadBinary<internal::IdentityConverter>(reader, header, adapter, flags);
2535 break;
2536 }
2537 if (!IsIEEE(arith_kind) || !IsIEEE(header.arith_kind))
2538 throw ReadError(name, 0, 0, "unsupported floating-point arithmetic");
2539 ReadBinary<internal::EndiannessConverter>(reader, header, adapter, flags);
2540 break;
2541 }
2542 }
2543 }
2544
2545 template <typename Handler>
2546 inline void ReadNLFile(fmt::CStringRef filename, Handler &handler, int flags) {
2547 internal::NLFileReader<>().Read(filename, handler, flags);
2548 }
2549 } // namespace mp
2550
2551 #endif // MP_NL_READER_H_
2552